From 29d46d000fe35633118bfaca970d17ba4c34c167 Mon Sep 17 00:00:00 2001 From: Peter Paul Bakker Date: Tue, 16 Nov 2021 10:11:20 +0100 Subject: [PATCH 1/2] added StandardErrorCallback class that can be registered via the errorCallback field in logging configs --- CHANGELOG.md | 4 + README.md | 4 +- pom.xml | 2 +- .../HttpEventCollectorErrorHandler.java | 47 +++++- .../HttpEventCollectorLog4jAppender.java | 5 + .../HttpEventCollectorLogbackAppender.java | 17 ++ .../HttpEventCollectorLoggingHandler.java | 11 ++ .../logging/HttpEventCollectorSender.java | 6 +- .../logging/util/StandardErrorCallback.java | 117 +++++++++++++ src/test/java/HttpEventCollectorUnitTest.java | 155 +++++++++++------- .../HttpEventCollectorUnitTestMiddleware.java | 27 ++- .../HttpEventCollector_JavaLoggingTest.java | 28 ++-- .../java/HttpEventCollector_Log4j2Test.java | 124 +++++++------- .../java/HttpEventCollector_LogbackTest.java | 13 +- src/test/java/HttpEventCollector_Test.java | 24 ++- .../HttpEventCollectorErrorHandlerTest.java | 90 ++++++++++ src/test/resources/log4j2_template.xml | 1 + src/test/resources/logback_template.xml | 1 + .../resources/logging_template.properties | 1 + 19 files changed, 506 insertions(+), 171 deletions(-) create mode 100644 src/main/java/com/splunk/logging/util/StandardErrorCallback.java create mode 100644 src/test/java/com/splunk/logging/HttpEventCollectorErrorHandlerTest.java diff --git a/CHANGELOG.md b/CHANGELOG.md index d73bbcb5..a5cbae17 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ # Splunk Logging for Java Changelog +## Version 1.12.0 + +* Added StandardErrorCallback. Register ErrorCallback implementations via logback or log4j xml config. (@stokpop) + ## Version 1.11.0 ### Minor Changes diff --git a/README.md b/README.md index 8b0bcbc2..77d5e336 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Splunk Logging for Java -#### Version 1.11.0 +#### Version 1.12.0 Splunk logging for Java enables you to log events to HTTP Event Collector or to a TCP input on a Splunk Enterprise instance within your Java applications. You can use three major Java logging frameworks: [Logback](http://logback.qos.ch), [Log4j 2](http://logging.apache.org/log4j/2.x/), and [java.util.logging](https://docs.oracle.com/javase/7/docs/api/java/util/logging/package-summary.html). Splunk logging for Java is also enabled for [Simple Logging Facade for Java (SLF4J)](http://www.slf4j.org). @@ -11,6 +11,8 @@ Splunk logging for Java provides: * Handler classes that export the logging events. * An optional error handler to catch failures for HTTP Event Collector events. + * Use `com.splunk.logging.util.StandardErrorCallback` to write errors to standard out. + * Use the `errorCallback` field in logging configs to register a ErrorCallback class. * Example configuration files for all three frameworks that show how to configure the frameworks to write to HTTP Event Collector or TCP ports. diff --git a/pom.xml b/pom.xml index 101b5400..4f2a671e 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ com.splunk.logging splunk-library-javalogging - 1.11.0 + 1.12.0-SNAPSHOT jar Splunk Logging for Java diff --git a/src/main/java/com/splunk/logging/HttpEventCollectorErrorHandler.java b/src/main/java/com/splunk/logging/HttpEventCollectorErrorHandler.java index b8e1074c..4a9f0cff 100644 --- a/src/main/java/com/splunk/logging/HttpEventCollectorErrorHandler.java +++ b/src/main/java/com/splunk/logging/HttpEventCollectorErrorHandler.java @@ -36,6 +36,26 @@ */ public class HttpEventCollectorErrorHandler { + /** + * Register error handler via full class name. + * + * When the class name is null or empty, null is registered to the HttpEventCollectorErrorHandler. + * + * @param errorCallbackClass the name of the class, for instance: com.splunk.logging.util.StandardErrorCallback + */ + public static void registerClassName(String errorCallbackClass) { + if (errorCallbackClass == null || errorCallbackClass.trim().isEmpty()) { + HttpEventCollectorErrorHandler.onError(null); + return; + } + try { + ErrorCallback callback = (ErrorCallback) Class.forName(errorCallbackClass).newInstance(); + HttpEventCollectorErrorHandler.onError(callback); + } catch (final Exception e) { + System.err.println("Warning: cannot create ErrorCallback instance: " + e); + } + } + /** * This exception is passed to error callback when Splunk server replies an error */ @@ -100,10 +120,26 @@ public interface ErrorCallback { private static ErrorCallback errorCallback; /** - * Register error callbacks - * @param callback ErrorCallback + * Register error callbacks. + * + * @param callback ErrorCallback Only one ErrorCallback can be registered. A new one will replace the old one. */ public static void onError(ErrorCallback callback) { + if (callback == null) { + logInfo("Reset ErrorCallback to null (no error handling)."); + } + else { + logInfo("Register ErrorCallback implementation: " + callback); + // onError() is called multiple times in unit tests and is also replaced intentionally. + // Issue a warning when it is replaced by a different kind of handler. + if (errorCallback != null && !errorCallback.equals(callback)) { + logWarn("ErrorCallback instance of '" + + errorCallback.getClass().getName() + + "' will be replaced by handler instance of '" + + callback.getClass().getName() + + "'"); + } + } errorCallback = callback; } @@ -117,4 +153,11 @@ public static void error(final List data, final Exc errorCallback.error(data, ex); } } + + private static void logInfo(String message) { + System.out.println("Info: " + message); + } + private static void logWarn(String message) { + System.out.println("Warning: " + message); + } } diff --git a/src/main/java/com/splunk/logging/HttpEventCollectorLog4jAppender.java b/src/main/java/com/splunk/logging/HttpEventCollectorLog4jAppender.java index 8afb25d4..c2cdab8f 100644 --- a/src/main/java/com/splunk/logging/HttpEventCollectorLog4jAppender.java +++ b/src/main/java/com/splunk/logging/HttpEventCollectorLog4jAppender.java @@ -148,6 +148,7 @@ public static HttpEventCollectorLog4jAppender createAppender( @PluginAttribute("disableCertificateValidation") final String disableCertificateValidation, @PluginAttribute("eventBodySerializer") final String eventBodySerializer, @PluginAttribute("eventHeaderSerializer") final String eventHeaderSerializer, + @PluginAttribute("errorCallback") final String errorCallback, @PluginAttribute(value = "includeLoggerName", defaultBoolean = true) final boolean includeLoggerName, @PluginAttribute(value = "includeThreadName", defaultBoolean = true) final boolean includeThreadName, @PluginAttribute(value = "includeMDC", defaultBoolean = true) final boolean includeMDC, @@ -203,6 +204,10 @@ public static HttpEventCollectorLog4jAppender createAppender( .build(); } + if (errorCallback != null) { + HttpEventCollectorErrorHandler.registerClassName(errorCallback); + } + final boolean ignoreExceptionsBool = Boolean.getBoolean(ignoreExceptions); return new HttpEventCollectorLog4jAppender( diff --git a/src/main/java/com/splunk/logging/HttpEventCollectorLogbackAppender.java b/src/main/java/com/splunk/logging/HttpEventCollectorLogbackAppender.java index af2a2c4a..c90e891c 100644 --- a/src/main/java/com/splunk/logging/HttpEventCollectorLogbackAppender.java +++ b/src/main/java/com/splunk/logging/HttpEventCollectorLogbackAppender.java @@ -47,6 +47,7 @@ public class HttpEventCollectorLogbackAppender extends AppenderBase { private String _middleware; private String _eventBodySerializer; private String _eventHeaderSerializer; + private String _errorCallback; private long _batchInterval = 0; private long _batchCount = 0; private long _batchSize = 0; @@ -107,6 +108,10 @@ public void start() { } catch (final Exception ignored) {} } + if (_errorCallback != null && !_errorCallback.isEmpty()) { + HttpEventCollectorErrorHandler.registerClassName(_errorCallback); + } + // plug resend middleware if (_retriesOnError > 0) { this.sender.addMiddleware(new HttpEventCollectorResendMiddleware(_retriesOnError)); @@ -305,6 +310,10 @@ public String getEventHeaderSerializer() { return _eventHeaderSerializer; } + public String getErrorHandler(String errorHandlerClass) { + return this._errorCallback; + } + public void setDisableCertificateValidation(String disableCertificateValidation) { this._disableCertificateValidation = disableCertificateValidation; } @@ -351,6 +360,14 @@ public void setEventHeaderSerializer(String eventHeaderSerializer) { this._eventHeaderSerializer = eventHeaderSerializer; } + public void setErrorCallback(String errorHandlerClass) { + this._errorCallback = errorHandlerClass; + } + + public String getErrorCallback() { + return this._errorCallback; + } + public void setConnectTimeout(long milliseconds) { this.timeoutSettings.connectTimeout = milliseconds; } diff --git a/src/main/java/com/splunk/logging/HttpEventCollectorLoggingHandler.java b/src/main/java/com/splunk/logging/HttpEventCollectorLoggingHandler.java index 912d4bd2..7361fe10 100644 --- a/src/main/java/com/splunk/logging/HttpEventCollectorLoggingHandler.java +++ b/src/main/java/com/splunk/logging/HttpEventCollectorLoggingHandler.java @@ -157,6 +157,7 @@ public HttpEventCollectorLoggingHandler() { String eventHeaderSerializer = getConfigurationProperty("eventHeaderSerializer", ""); String middleware = getConfigurationProperty(MiddlewareTag, null); String eventBodySerializer = getConfigurationProperty("eventBodySerializer", null); + String errorCallbackClass = getConfigurationProperty("errorCallback", null); includeLoggerName = getConfigurationBooleanProperty(IncludeLoggerNameConfTag, true); includeThreadName = getConfigurationBooleanProperty(IncludeThreadNameConfTag, true); @@ -208,6 +209,16 @@ public HttpEventCollectorLoggingHandler() { } } + if (errorCallbackClass != null && !errorCallbackClass.isEmpty()) { + try { + HttpEventCollectorErrorHandler.registerClassName(errorCallbackClass); + } catch (final Exception ex) { + //output error msg but not fail, it will default to use the default EventHeaderSerializer + System.out.println(ex); + } + } + + // plug retries middleware if (retriesOnError > 0) { this.sender.addMiddleware(new HttpEventCollectorResendMiddleware(retriesOnError)); diff --git a/src/main/java/com/splunk/logging/HttpEventCollectorSender.java b/src/main/java/com/splunk/logging/HttpEventCollectorSender.java index c5ddfda8..8fd0aa77 100644 --- a/src/main/java/com/splunk/logging/HttpEventCollectorSender.java +++ b/src/main/java/com/splunk/logging/HttpEventCollectorSender.java @@ -363,10 +363,8 @@ public void completed(int statusCode, String reply) { } @Override - public void failed(Exception ex) { - HttpEventCollectorErrorHandler.error( - events, - new HttpEventCollectorErrorHandler.ServerErrorException(ex.getMessage())); + public void failed(Exception exception) { + HttpEventCollectorErrorHandler.error(events, exception); } }); } diff --git a/src/main/java/com/splunk/logging/util/StandardErrorCallback.java b/src/main/java/com/splunk/logging/util/StandardErrorCallback.java new file mode 100644 index 00000000..05cd6490 --- /dev/null +++ b/src/main/java/com/splunk/logging/util/StandardErrorCallback.java @@ -0,0 +1,117 @@ +package com.splunk.logging.util; + +import com.splunk.logging.HttpEventCollectorErrorHandler; +import com.splunk.logging.HttpEventCollectorEventInfo; + +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.time.format.DateTimeFormatterBuilder; +import java.util.List; +import java.util.Locale; +import java.util.concurrent.atomic.AtomicInteger; + +/** + * Print errors to standard out because sending events to Splunk has exceptions and + * logging frameworks might be disabled or broken. + * + * Enable printStackTraces via property: -Dcom.splunk.logging.util.StandardErrorCallback.enablePrintStackTrace=true + */ +public class StandardErrorCallback implements HttpEventCollectorErrorHandler.ErrorCallback { + + public static final Locale DEFAULT_LOCALE = Locale.US; + + private static final AtomicInteger eventCount = new AtomicInteger(0); + private static final AtomicInteger errorCount = new AtomicInteger(0); + + private static final DateTimeFormatter HUMAN_READABLE_WITH_MILLIS = + new DateTimeFormatterBuilder().appendPattern("yyyy-MM-dd HH:mm:ss.SSS").toFormatter(DEFAULT_LOCALE); + + private final boolean enablePrintStackTrace; + + public StandardErrorCallback() { + this(checkEnablePrintStackTrace()); + } + + private static boolean checkEnablePrintStackTrace() { + return "true".equalsIgnoreCase(System.getProperty("com.splunk.logging.util.StandardErrorCallback.enablePrintStackTrace", "false")); + } + + public StandardErrorCallback(boolean enablePrintStackTrace) { + this.enablePrintStackTrace = enablePrintStackTrace; + } + + @Override + public void error(List data, Exception ex) { + int totalErrorCount = errorCount.incrementAndGet(); + int totalEventCount = eventCount.addAndGet(data == null ? 0 : data.size()); + + String threadName = Thread.currentThread().getName(); + + String fullMessage = createErrorMessage(data, ex, totalErrorCount, totalEventCount, threadName); + + printError(fullMessage); + + printStackTrace(ex); + } + + private String createErrorMessage(List data, Exception ex, int totalErrorCount, int totalEventCount, String threadName) { + + String timestamp = HUMAN_READABLE_WITH_MILLIS.format(LocalDateTime.now()); + String exceptionMessage = ex == null ? "unknown (exception null)" : ex.getClass().getSimpleName() + ": " + ex.getMessage(); + + final String batchOrSingleText = createBatchOrSingleText(data); + + String fullMessage = timestamp + + " [" + threadName + "] HttpEventCollectorError exception for " + + batchOrSingleText + ". Total errors/events: " + totalErrorCount + "/" + totalEventCount + ". Message: " + exceptionMessage; + + return fullMessage; + } + + private String createBatchOrSingleText(List data) { + final String batchOrSingleText; + if (data == null) { + batchOrSingleText = "unknown events (data is null)"; + } + else { + int size = data.size(); + if (size == 1) { + batchOrSingleText = "log event"; + } else { + batchOrSingleText = "batch of " + size + " log events"; + } + } + return batchOrSingleText; + } + + private void printStackTrace(Exception ex) { + if (enablePrintStackTrace) { + if (ex != null) { + ex.printStackTrace(); + } + } + } + + private void printError(String fullMessage) { + System.err.println(fullMessage); + } + + public int getEventCount() { + return eventCount.get(); + } + + public int getErrorCount() { + return errorCount.get(); + } + + public void resetCounters() { + // should maybe be atomic thread safe action, complicated, good enough? + errorCount.set(0); + eventCount.set(0); + } + + public boolean isPrintStackTraceEnabled() { + return enablePrintStackTrace; + } + +} diff --git a/src/test/java/HttpEventCollectorUnitTest.java b/src/test/java/HttpEventCollectorUnitTest.java index 2961934b..e334e3bc 100644 --- a/src/test/java/HttpEventCollectorUnitTest.java +++ b/src/test/java/HttpEventCollectorUnitTest.java @@ -16,22 +16,16 @@ * under the License. */ -import java.io.IOException; -import java.io.OutputStream; -import java.net.InetSocketAddress; - import com.splunk.logging.HttpEventCollectorErrorHandler; import com.splunk.logging.HttpEventCollectorEventInfo; import org.junit.Assert; import org.junit.Test; -import sun.rmi.runtime.Log; import java.io.ByteArrayInputStream; -import java.util.Date; +import java.io.IOException; import java.util.HashMap; import java.util.List; import java.util.logging.LogManager; -import java.util.logging.Logger; public class HttpEventCollectorUnitTest { @Test @@ -43,19 +37,20 @@ public void log4j_simple() throws Exception { userInputs.put("user_middleware", "HttpEventCollectorUnitTestMiddleware"); userInputs.put("user_batch_size_count", "1"); userInputs.put("user_batch_size_bytes", "0"); - userInputs.put("user_eventBodySerializer", "DoesNotExistButShouldNotCrashTest"); - userInputs.put("user_eventHeaderSerializer", "DoesNotExistButShouldNotCrashTest"); + userInputs.put("user_eventBodySerializer", "BodySerializerDoesNotExistButShouldNotCrashTest"); + userInputs.put("user_eventHeaderSerializer", "HeaderSerializerDoesNotExistButShouldNotCrashTest"); + userInputs.put("user_errorCallback", "ErrorCallbackHeaderSerializerDoesNotExistButShouldNotCrashTest"); TestUtil.resetLog4j2Configuration("log4j2_template.xml", "log4j2.xml", userInputs); org.apache.logging.log4j.Logger LOG4J = org.apache.logging.log4j.LogManager.getLogger(loggerName); // send 3 events - HttpEventCollectorUnitTestMiddleware.eventsReceived = 0; + HttpEventCollectorUnitTestMiddleware.resetCounters(); HttpEventCollectorUnitTestMiddleware.io = new HttpEventCollectorUnitTestMiddleware.IO() { @Override public void input(List events) { - Assert.assertTrue(events.size() == 1); - Assert.assertTrue(events.get(0).getMessage().compareTo("hello log4j") == 0); - Assert.assertTrue(events.get(0).getSeverity().compareTo("INFO") == 0); + Assert.assertEquals(1, events.size()); + Assert.assertEquals(0, events.get(0).getMessage().compareTo("hello log4j")); + Assert.assertEquals(0, events.get(0).getSeverity().compareTo("INFO")); } }; LOG4J.info("hello log4j"); @@ -63,7 +58,40 @@ public void input(List events) { LOG4J.info("hello log4j"); if (HttpEventCollectorUnitTestMiddleware.eventsReceived == 0) sleep(15000); - Assert.assertTrue(HttpEventCollectorUnitTestMiddleware.eventsReceived == 3); + Assert.assertEquals(3, HttpEventCollectorUnitTestMiddleware.eventsReceived); + Assert.assertEquals(0, HttpEventCollectorUnitTestMiddleware.eventsWithFailures); + } + + @Test + public void log4j_simple_with_errorCallback() throws Exception { + HashMap userInputs = new HashMap<>(); + String loggerName = "splunk.log4jSimple"; + userInputs.put("user_logger_name", loggerName); + userInputs.put("user_httpEventCollector_token", "11111111-2222-3333-4444-555555555555"); + userInputs.put("user_middleware", "HttpEventCollectorUnitTestMiddleware"); + userInputs.put("user_batch_size_count", "1"); + userInputs.put("user_batch_size_bytes", "0"); + userInputs.put("user_eventBodySerializer", "BodySerializerDoesNotExistButShouldNotCrashTest"); + userInputs.put("user_eventHeaderSerializer", "HeaderSerializerDoesNotExistButShouldNotCrashTest"); + userInputs.put("user_errorCallback", "com.splunk.logging.util.StandardErrorCallback"); + TestUtil.resetLog4j2Configuration("log4j2_template.xml", "log4j2.xml", userInputs); + org.apache.logging.log4j.Logger LOG4J = org.apache.logging.log4j.LogManager.getLogger(loggerName); + + // send 3 events + HttpEventCollectorUnitTestMiddleware.resetCounters(); + HttpEventCollectorUnitTestMiddleware.io = new HttpEventCollectorUnitTestMiddleware.IO() { + @Override + public void input(List events) { + } + + @Override + public HttpEventCollectorUnitTestMiddleware.HttpResponse output() { + throw new IllegalArgumentException("call failure"); + } + }; + LOG4J.info("hello log4j"); + Assert.assertEquals(1, HttpEventCollectorUnitTestMiddleware.eventsReceived); + Assert.assertEquals(1, HttpEventCollectorUnitTestMiddleware.eventsWithFailures); } @Test @@ -73,26 +101,28 @@ public void logback_simple() throws Exception { userInputs.put("user_logger_name", loggerName); userInputs.put("user_httpEventCollector_token", "11111111-2222-3333-4444-555555555555"); userInputs.put("user_middleware", "HttpEventCollectorUnitTestMiddleware"); - userInputs.put("user_eventBodySerializer", "DoesNotExistButShouldNotCrashTest"); - userInputs.put("user_eventHeaderSerializer", "DoesNotExistButShouldNotCrashTest"); + userInputs.put("user_eventBodySerializer", "BodySerializerDoesNotExistButShouldNotCrashTest"); + userInputs.put("user_eventHeaderSerializer", "HeaderSerializerDoesNotExistButShouldNotCrashTest"); + userInputs.put("user_errorCallback", "ErrorCallbackDoesNotExistButShouldNotCrashTest"); TestUtil.resetLogbackConfiguration("logback_template.xml", "logback.xml", userInputs); org.slf4j.Logger LOGBACK = org.slf4j.LoggerFactory.getLogger(loggerName); // send 3 events - HttpEventCollectorUnitTestMiddleware.eventsReceived = 0; + HttpEventCollectorUnitTestMiddleware.resetCounters();; HttpEventCollectorUnitTestMiddleware.io = new HttpEventCollectorUnitTestMiddleware.IO() { @Override public void input(List events) { - Assert.assertTrue(events.size() == 1); - Assert.assertTrue(events.get(0).getMessage().compareTo("hello logback") == 0); - Assert.assertTrue(events.get(0).getSeverity().compareTo("ERROR") == 0); - Assert.assertTrue(events.get(0).getLoggerName().compareTo(loggerName) == 0); + Assert.assertEquals(1, events.size()); + Assert.assertEquals(0, events.get(0).getMessage().compareTo("hello logback")); + Assert.assertEquals(0, events.get(0).getSeverity().compareTo("ERROR")); + Assert.assertEquals(0, events.get(0).getLoggerName().compareTo(loggerName)); } }; LOGBACK.error("hello logback"); LOGBACK.error("hello logback"); LOGBACK.error("hello logback"); - Assert.assertTrue(HttpEventCollectorUnitTestMiddleware.eventsReceived == 3); + Assert.assertEquals(3, HttpEventCollectorUnitTestMiddleware.eventsReceived); + Assert.assertEquals(0, HttpEventCollectorUnitTestMiddleware.eventsWithFailures); } @Test @@ -106,24 +136,26 @@ public void java_util_logger_simple() { "com.splunk.logging.HttpEventCollectorLoggingHandler.batch_size_bytes=0\n" + "com.splunk.logging.HttpEventCollectorLoggingHandler.batch_interval=0\n" + "com.splunk.logging.HttpEventCollectorLoggingHandler.middleware=HttpEventCollectorUnitTestMiddleware\n" + - "com.splunk.logging.HttpEventCollectorLoggingHandler.eventBodySerializer=DoesNotExistButShouldNotCrashTest\n" + - "com.splunk.logging.HttpEventCollectorLoggingHandler.eventHeaderSerializer=DoesNotExistButShouldNotCrashTest\n" + "com.splunk.logging.HttpEventCollectorLoggingHandler.errorCallback=com.splunk.logging.util.StandardErrorCallback\n" + + "com.splunk.logging.HttpEventCollectorLoggingHandler.eventBodySerializer=BodySerializerDoesNotExistButShouldNotCrashTest\n" + + "com.splunk.logging.HttpEventCollectorLoggingHandler.eventHeaderSerializer=HeaderSerializerDoesNotExistButShouldNotCrashTest\n" ); // send 3 events - HttpEventCollectorUnitTestMiddleware.eventsReceived = 0; + HttpEventCollectorUnitTestMiddleware.resetCounters(); HttpEventCollectorUnitTestMiddleware.io = new HttpEventCollectorUnitTestMiddleware.IO() { @Override public void input(List events) { - Assert.assertTrue(events.size() == 1); - Assert.assertTrue(events.get(0).getMessage().compareTo("hello java logger") == 0); - Assert.assertTrue(events.get(0).getSeverity().compareTo("WARNING") == 0); + Assert.assertEquals(1, events.size()); + Assert.assertEquals(0, events.get(0).getMessage().compareTo("hello java logger")); + Assert.assertEquals(0, events.get(0).getSeverity().compareTo("WARNING")); } }; LOGGER.warning("hello java logger"); LOGGER.warning("hello java logger"); LOGGER.warning("hello java logger"); - Assert.assertTrue(HttpEventCollectorUnitTestMiddleware.eventsReceived == 3); + Assert.assertEquals(3, HttpEventCollectorUnitTestMiddleware.eventsReceived); + Assert.assertEquals(0, HttpEventCollectorUnitTestMiddleware.eventsWithFailures); } @Test @@ -140,7 +172,7 @@ public void java_util_logger_error_handler() { ); // mimic server 404 - HttpEventCollectorUnitTestMiddleware.eventsReceived = 0; + HttpEventCollectorUnitTestMiddleware.resetCounters(); HttpEventCollectorUnitTestMiddleware.io = new HttpEventCollectorUnitTestMiddleware.IO() { @Override public HttpEventCollectorUnitTestMiddleware.HttpResponse output() { @@ -149,16 +181,15 @@ public HttpEventCollectorUnitTestMiddleware.HttpResponse output() { ); } }; - HttpEventCollectorErrorHandler.onError(new HttpEventCollectorErrorHandler.ErrorCallback() { - public void error(final List data, final Exception ex) { - HttpEventCollectorErrorHandler.ServerErrorException serverErrorException = - (HttpEventCollectorErrorHandler.ServerErrorException) ex; - Assert.assertTrue(serverErrorException.getReply().compareTo("{\"text\":\"error\",\"code\":4}") == 0); - Assert.assertTrue(serverErrorException.getErrorCode() == 4); - } + HttpEventCollectorErrorHandler.onError((data, ex) -> { + HttpEventCollectorErrorHandler.ServerErrorException serverErrorException = + (HttpEventCollectorErrorHandler.ServerErrorException) ex; + Assert.assertEquals(0, serverErrorException.getReply().compareTo("{\"text\":\"error\",\"code\":4}")); + Assert.assertEquals(4, serverErrorException.getErrorCode()); }); LOGGER.info("hello"); - Assert.assertTrue(HttpEventCollectorUnitTestMiddleware.eventsReceived == 1); + Assert.assertEquals(1, HttpEventCollectorUnitTestMiddleware.eventsReceived); + Assert.assertEquals(1, HttpEventCollectorUnitTestMiddleware.eventsWithFailures); } @Test @@ -175,13 +206,13 @@ public void java_util_logger_resend() { "com.splunk.logging.HttpEventCollectorLoggingHandler.retries_on_error=2\n" ); - HttpEventCollectorUnitTestMiddleware.eventsReceived = 0; + HttpEventCollectorUnitTestMiddleware.resetCounters(); HttpEventCollectorUnitTestMiddleware.io = new HttpEventCollectorUnitTestMiddleware.IO() { int retries = 0; @Override public void input(List events) { - Assert.assertTrue(events.get(0).getMessage().compareTo("hello") == 0); - Assert.assertTrue(events.get(0).getSeverity().compareTo("INFO") == 0); + Assert.assertEquals(0, events.get(0).getMessage().compareTo("hello")); + Assert.assertEquals(0, events.get(0).getSeverity().compareTo("INFO")); } @Override public HttpEventCollectorUnitTestMiddleware.HttpResponse output() { @@ -198,7 +229,8 @@ public HttpEventCollectorUnitTestMiddleware.HttpResponse output() { }; LOGGER.info("hello"); // the system should make 2 retries - Assert.assertTrue(HttpEventCollectorUnitTestMiddleware.eventsReceived == 2); + Assert.assertEquals(2, HttpEventCollectorUnitTestMiddleware.eventsReceived); + Assert.assertEquals(1, HttpEventCollectorUnitTestMiddleware.eventsWithFailures); } @Test @@ -215,12 +247,12 @@ public void java_util_logger_resend_max_retries() { "com.splunk.logging.HttpEventCollectorLoggingHandler.retries_on_error=2\n" ); - HttpEventCollectorUnitTestMiddleware.eventsReceived = 0; + HttpEventCollectorUnitTestMiddleware.resetCounters(); HttpEventCollectorUnitTestMiddleware.io = new HttpEventCollectorUnitTestMiddleware.IO() { @Override public void input(List events) { - Assert.assertTrue(events.get(0).getMessage().compareTo("hello") == 0); - Assert.assertTrue(events.get(0).getSeverity().compareTo("INFO") == 0); + Assert.assertEquals(0, events.get(0).getMessage().compareTo("hello")); + Assert.assertEquals(0, events.get(0).getSeverity().compareTo("INFO")); } @Override public HttpEventCollectorUnitTestMiddleware.HttpResponse output() { @@ -236,7 +268,7 @@ public void error(final List data, final Exception }); LOGGER.info("hello"); // the system should make only 2 retries and stop after that - Assert.assertTrue(HttpEventCollectorUnitTestMiddleware.eventsReceived == 3); + Assert.assertEquals(3, HttpEventCollectorUnitTestMiddleware.eventsReceived); } @Test @@ -250,20 +282,21 @@ public void java_util_logger_batching() { "com.splunk.logging.HttpEventCollectorLoggingHandler.batch_size_count=3\n" ); - HttpEventCollectorUnitTestMiddleware.eventsReceived = 0; + HttpEventCollectorUnitTestMiddleware.resetCounters(); HttpEventCollectorUnitTestMiddleware.io = new HttpEventCollectorUnitTestMiddleware.IO() { @Override public void input(List events) { - Assert.assertTrue(events.size() == 3); - Assert.assertTrue(events.get(0).getMessage().compareTo("one") == 0); - Assert.assertTrue(events.get(1).getMessage().compareTo("two") == 0); - Assert.assertTrue(events.get(2).getMessage().compareTo("three") == 0); + Assert.assertEquals(3, events.size()); + Assert.assertEquals(0, events.get(0).getMessage().compareTo("one")); + Assert.assertEquals(0, events.get(1).getMessage().compareTo("two")); + Assert.assertEquals(0, events.get(2).getMessage().compareTo("three")); } }; LOGGER.info("one"); LOGGER.info("two"); LOGGER.info("three"); - Assert.assertTrue(HttpEventCollectorUnitTestMiddleware.eventsReceived == 3); + Assert.assertEquals(3, HttpEventCollectorUnitTestMiddleware.eventsReceived); + Assert.assertEquals(0, HttpEventCollectorUnitTestMiddleware.eventsWithFailures); } @Test @@ -276,7 +309,7 @@ public void java_util_logger_batching_default_count() { "com.splunk.logging.HttpEventCollectorLoggingHandler.middleware=HttpEventCollectorUnitTestMiddleware\n" ); final int DefaultBatchCount = 10; - HttpEventCollectorUnitTestMiddleware.eventsReceived = 0; + HttpEventCollectorUnitTestMiddleware.resetCounters(); HttpEventCollectorUnitTestMiddleware.io = new HttpEventCollectorUnitTestMiddleware.IO() { @Override public void input(List events) { @@ -286,7 +319,8 @@ public void input(List events) { for (int i = 0; i < DefaultBatchCount * 100; i ++) { LOGGER.info("*"); } - Assert.assertTrue(HttpEventCollectorUnitTestMiddleware.eventsReceived == DefaultBatchCount * 100); + Assert.assertEquals(DefaultBatchCount * 100, HttpEventCollectorUnitTestMiddleware.eventsReceived); + Assert.assertEquals(0, HttpEventCollectorUnitTestMiddleware.eventsWithFailures); } @Test @@ -299,17 +333,18 @@ public void java_util_logger_batching_default_size() { "com.splunk.logging.HttpEventCollectorLoggingHandler.middleware=HttpEventCollectorUnitTestMiddleware\n" ); final int DefaultBatchSize = 10 * 1024; - HttpEventCollectorUnitTestMiddleware.eventsReceived = 0; + HttpEventCollectorUnitTestMiddleware.resetCounters(); HttpEventCollectorUnitTestMiddleware.io = new HttpEventCollectorUnitTestMiddleware.IO() { @Override public void input(List events) { - Assert.assertTrue(events.size() == 1); + Assert.assertEquals(1, events.size()); } }; for (int i = 0; i < 10; i ++) { LOGGER.info(repeat("x", DefaultBatchSize)); } - Assert.assertTrue(HttpEventCollectorUnitTestMiddleware.eventsReceived == 10); + Assert.assertEquals(10, HttpEventCollectorUnitTestMiddleware.eventsReceived); + Assert.assertEquals(0, HttpEventCollectorUnitTestMiddleware.eventsWithFailures); } @Test @@ -322,18 +357,20 @@ public void java_util_logger_batching_default_interval() { "com.splunk.logging.HttpEventCollectorLoggingHandler.middleware=HttpEventCollectorUnitTestMiddleware\n" ); final int DefaultInterval = 10000; - HttpEventCollectorUnitTestMiddleware.eventsReceived = 0; + HttpEventCollectorUnitTestMiddleware.resetCounters(); HttpEventCollectorUnitTestMiddleware.io = new HttpEventCollectorUnitTestMiddleware.IO() { @Override public void input(List events) { - Assert.assertTrue(events.size() == 1); + Assert.assertEquals(1, events.size()); } }; LOGGER.info("=|:-)"); sleep(DefaultInterval / 2); Assert.assertTrue(HttpEventCollectorUnitTestMiddleware.eventsReceived == 0); + Assert.assertEquals(0, HttpEventCollectorUnitTestMiddleware.eventsWithFailures); sleep(DefaultInterval); Assert.assertTrue(HttpEventCollectorUnitTestMiddleware.eventsReceived == 1); + Assert.assertEquals(0, HttpEventCollectorUnitTestMiddleware.eventsWithFailures); } //-------------------------------------------------------------------------- diff --git a/src/test/java/HttpEventCollectorUnitTestMiddleware.java b/src/test/java/HttpEventCollectorUnitTestMiddleware.java index 0d272cd0..bc2debe4 100644 --- a/src/test/java/HttpEventCollectorUnitTestMiddleware.java +++ b/src/test/java/HttpEventCollectorUnitTestMiddleware.java @@ -31,11 +31,22 @@ public void postEvents(List events, HttpEventCollectorMiddleware.IHttpSenderCallback callback) { eventsReceived += events.size(); io.input(events); - HttpResponse response = io.output(); - if (response.status > 0) - callback.completed(response.status, response.reply); - else - callback.failed(new Exception(response.reply)); + try { + HttpResponse response = io.output(); + if (response.status > 0) { + // this is what actually happens within the callback completed + // but then we cannot count the eventsWithFailures + if (response.status != 200) { eventsWithFailures = eventsWithFailures + 1;} + callback.completed(response.status, response.reply); + } + else { + eventsWithFailures = eventsWithFailures + 1; + callback.failed(new Exception(response.reply)); + } + } catch (Exception exception) { + eventsWithFailures = eventsWithFailures + 1; + callback.failed(exception); + } } public static class HttpResponse { @@ -56,4 +67,10 @@ public void input(List events) {} public static IO io = new IO(); public static int eventsReceived = 0; + public static int eventsWithFailures = 0; + + public static void resetCounters() { + eventsReceived = 0; + eventsWithFailures = 0; + } } diff --git a/src/test/java/HttpEventCollector_JavaLoggingTest.java b/src/test/java/HttpEventCollector_JavaLoggingTest.java index 32127d78..50204ff2 100644 --- a/src/test/java/HttpEventCollector_JavaLoggingTest.java +++ b/src/test/java/HttpEventCollector_JavaLoggingTest.java @@ -31,7 +31,7 @@ public final class HttpEventCollector_JavaLoggingTest { private String httpEventCollectorName = "JavaLoggingTest"; List> errors = new ArrayList>(); - List logEx = new ArrayList(); + List logEx = new ArrayList<>(); /** * sending a message via httplogging using java.logging to splunk @@ -236,12 +236,10 @@ public void errorHandlingInvalidToken() throws Exception { errors.clear(); logEx.clear(); //define error callback - HttpEventCollectorErrorHandler.onError(new HttpEventCollectorErrorHandler.ErrorCallback() { - public void error(final List data, final Exception ex) { - synchronized (errors) { - errors.add(data); - logEx.add((HttpEventCollectorErrorHandler.ServerErrorException) ex); - } + HttpEventCollectorErrorHandler.onError((data, ex) -> { + synchronized (errors) { + errors.add(data); + logEx.add(ex); } }); @@ -282,8 +280,10 @@ public void error(final List data, final Exception System.out.println("======print logEx"); System.out.println(logEx.toString()); System.out.println("======finish print logEx"); - Assert.assertEquals("Invalid token", logEx.get(1).getErrorText()); - Assert.assertEquals(4, logEx.get(1).getErrorCode()); + // in this case expect a valid http reply with a json error message + HttpEventCollectorErrorHandler.ServerErrorException serverErrorException = (HttpEventCollectorErrorHandler.ServerErrorException) logEx.get(1); + Assert.assertEquals("Invalid token", serverErrorException.getErrorText()); + Assert.assertEquals(4, serverErrorException.getErrorCode()); for (List infos : errors) { @@ -304,12 +304,10 @@ public void errorHandlingDisabledHttpEventCollectorEndpoint() throws Exception { logEx.clear(); //define error callback - HttpEventCollectorErrorHandler.onError(new HttpEventCollectorErrorHandler.ErrorCallback() { - public void error(final List data, final Exception ex) { - synchronized (errors) { - errors.add(data); - logEx.add((HttpEventCollectorErrorHandler.ServerErrorException) ex); - } + HttpEventCollectorErrorHandler.onError((data, ex) -> { + synchronized (errors) { + errors.add(data); + logEx.add(ex); } }); diff --git a/src/test/java/HttpEventCollector_Log4j2Test.java b/src/test/java/HttpEventCollector_Log4j2Test.java index b049f812..cb10fec2 100644 --- a/src/test/java/HttpEventCollector_Log4j2Test.java +++ b/src/test/java/HttpEventCollector_Log4j2Test.java @@ -14,48 +14,49 @@ * under the License. */ -import java.io.*; -import java.util.*; - import com.google.gson.JsonObject; import com.google.gson.JsonPrimitive; import com.splunk.logging.HttpEventCollectorErrorHandler; import com.splunk.logging.HttpEventCollectorEventInfo; - import org.apache.commons.lang3.StringUtils; +import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.core.LoggerContext; import org.junit.Assert; import org.junit.Test; -import org.apache.logging.log4j.Logger; + +import java.util.ArrayList; +import java.util.Date; +import java.util.HashMap; +import java.util.List; public final class HttpEventCollector_Log4j2Test { private String httpEventCollectorName = "Log4j2Test"; - List> errors = new ArrayList>(); - List logEx = new ArrayList<>(); + final List> errors = new ArrayList<>(); + final List logEx = new ArrayList<>(); /** * sending a message via httplogging using log4j2 to splunk */ @Test - public void canSendEventUsingLog4j2() throws Exception, IOException, InterruptedException { + public void canSendEventUsingLog4j2() throws Exception { TestUtil.enableHttpEventCollector(); String token = TestUtil.createHttpEventCollectorToken(httpEventCollectorName); String loggerName = "splunkLogger4j2"; - HashMap userInputs = new HashMap(); + HashMap userInputs = new HashMap<>(); userInputs.put("user_logger_name", loggerName); userInputs.put("user_httpEventCollector_token", token); org.apache.logging.log4j.core.LoggerContext context = TestUtil.resetLog4j2Configuration("log4j2_template.xml", "log4j2.xml", userInputs); //use httplogger - List msgs = new ArrayList(); + List msgs = new ArrayList<>(); Date date = new Date(); - String jsonMsg = String.format("{EventDate:%s, EventMsg:'this is a test event for log4j2}", date.toString()); + String jsonMsg = String.format("{EventDate:%s, EventMsg:'this is a test event for log4j2}", date); Logger logger = context.getLogger(loggerName); logger.info(jsonMsg); msgs.add(jsonMsg); - jsonMsg = String.format("{EventDate:%s, EventMsg:'this is a test error for log4j2}", date.toString()); + jsonMsg = String.format("{EventDate:%s, EventMsg:'this is a test error for log4j2}", date); logger.error(jsonMsg); msgs.add(jsonMsg); @@ -70,11 +71,11 @@ public void canSendEventUsingLog4j2() throws Exception, IOException, Interrupted * sending a message via httplogging using log4j2 to splunk and set index, source and sourcetype */ @Test - public void canSendEventUsingLog4j2WithOptions() throws Exception, IOException, InterruptedException { + public void canSendEventUsingLog4j2WithOptions() throws Exception { String token = TestUtil.createHttpEventCollectorToken(httpEventCollectorName); String loggerName = "splunkLogger4j2WithOptions"; - HashMap userInputs = new HashMap(); + HashMap userInputs = new HashMap<>(); userInputs.put("user_logger_name", loggerName); userInputs.put("user_httpEventCollector_token", token); userInputs.put("user_index", "main"); @@ -84,16 +85,16 @@ public void canSendEventUsingLog4j2WithOptions() throws Exception, IOException, org.apache.logging.log4j.core.LoggerContext context = TestUtil.resetLog4j2Configuration("log4j2_template.xml", "log4j2.xml", userInputs); //use httplogger - List msgs = new ArrayList(); + List msgs = new ArrayList<>(); Date date = new Date(); - String jsonMsg = String.format("{EventDate:%s, EventMsg:'this is a test event for log4j2}", date.toString()); + String jsonMsg = String.format("{EventDate:%s, EventMsg:'this is a test event for log4j2}", date); Logger logger = context.getLogger(loggerName); logger.info(jsonMsg); msgs.add(jsonMsg); - jsonMsg = String.format("{EventDate:%s, EventMsg:'this is a test error for log4j2}", date.toString()); + jsonMsg = String.format("{EventDate:%s, EventMsg:'this is a test error for log4j2}", date); logger.error(jsonMsg); msgs.add(jsonMsg); @@ -112,21 +113,20 @@ public void sendBatchedEventsByCount() throws Exception { //clean out the events cache by setting send events immediately String loggerName = "splunkLoggerCountCleanCache"; - HashMap userInputs = new HashMap(); + HashMap userInputs = new HashMap<>(); userInputs.put("user_logger_name", loggerName); userInputs.put("user_httpEventCollector_token", token); LoggerContext context = TestUtil.resetLog4j2Configuration("log4j2_template.xml", "log4j2.xml", userInputs); - String jsonMsg = String.format("{EventDate:%s, EventMsg:'this is a test event for java logging}", new Date().toString()); + String jsonMsg = String.format("{EventDate:%s, EventMsg:'this is a test event for java logging}", new Date()); Logger logger = context.getLogger(loggerName); logger.info(jsonMsg); loggerName = "splunkBatchLoggerCount"; - userInputs = new HashMap(); + userInputs = new HashMap<>(); userInputs.put("user_logger_name", loggerName); userInputs.put("user_httpEventCollector_token", token); userInputs.put("user_batch_interval","0"); userInputs.put("user_batch_size_count", "5"); - userInputs.put("user_logger_name", loggerName); userInputs.put("user_host", "host.example.com"); userInputs.put("user_source", "splunktest_BatchCount"); userInputs.put("user_sourcetype", "battlecat_BatchCount"); @@ -134,24 +134,24 @@ public void sendBatchedEventsByCount() throws Exception { context = TestUtil.resetLog4j2Configuration("log4j2_template.xml", "log4j2.xml", userInputs); logger = context.getLogger(loggerName); - List msgs = new ArrayList(); + List msgs = new ArrayList<>(); - jsonMsg = String.format("{EventDate:%s, EventMsg:'this is a test event for java logging1}", new Date().toString()); + jsonMsg = String.format("{EventDate:%s, EventMsg:'this is a test event for java logging1}", new Date()); logger.info(jsonMsg); msgs.add(jsonMsg); System.out.println("event 1"); TestUtil.verifyNoEventSentToSplunk(msgs); - jsonMsg = String.format("{EventDate:%s, EventMsg:'this is a test event for java logging2}", new Date().toString()); + jsonMsg = String.format("{EventDate:%s, EventMsg:'this is a test event for java logging2}", new Date()); logger.info(jsonMsg); msgs.add(jsonMsg); System.out.println("event 2"); TestUtil.verifyNoEventSentToSplunk(msgs); - jsonMsg = String.format("{EventDate:%s, EventMsg:'this is a test event for java logging3}", new Date().toString()); + jsonMsg = String.format("{EventDate:%s, EventMsg:'this is a test event for java logging3}", new Date()); logger.info(jsonMsg); msgs.add(jsonMsg); System.out.println("event 3"); TestUtil.verifyNoEventSentToSplunk(msgs); - jsonMsg = String.format("{EventDate:%s, EventMsg:'this is a test event for java logging4}", new Date().toString()); + jsonMsg = String.format("{EventDate:%s, EventMsg:'this is a test event for java logging4}", new Date()); logger.info(jsonMsg); msgs.add(jsonMsg); System.out.println("event 4"); @@ -160,7 +160,7 @@ public void sendBatchedEventsByCount() throws Exception { Thread.sleep(6000); TestUtil.verifyNoEventSentToSplunk(msgs); - jsonMsg = String.format("{EventDate:%s, EventMsg:'this is a test event for java logging5}", new Date().toString()); + jsonMsg = String.format("{EventDate:%s, EventMsg:'this is a test event for java logging5}", new Date()); logger.info(jsonMsg); msgs.add(jsonMsg); @@ -176,7 +176,7 @@ public void sendBatchedEventsByCount() throws Exception { public void sendBatchedEventsByBatchsize() throws Exception { String token = TestUtil.createHttpEventCollectorToken(httpEventCollectorName); String loggerName = "splunkLoggerBatchSize"; - HashMap userInputs = new HashMap(); + HashMap userInputs = new HashMap<>(); userInputs.put("user_logger_name", loggerName); userInputs.put("user_httpEventCollector_token", token); userInputs.put("user_batch_size_bytes", "500"); @@ -188,13 +188,13 @@ public void sendBatchedEventsByBatchsize() throws Exception { LoggerContext context = TestUtil.resetLog4j2Configuration("log4j2_template.xml", "log4j2.xml", userInputs); Logger logger = context.getLogger(loggerName); - List msgs = new ArrayList(); + List msgs = new ArrayList<>(); int size = 0; - String jsonMsg = String.format("{EventDate:%s, EventMsg:'test event for log4j size 1}", new Date().toString()); + String jsonMsg = String.format("{EventDate:%s, EventMsg:'test event for log4j size 1}", new Date()); logger.info(jsonMsg); size += jsonMsg.length(); msgs.add(jsonMsg); - jsonMsg = String.format("{EventDate:%s, EventMsg:'test event for log4j size 2}", new Date().toString()); + jsonMsg = String.format("{EventDate:%s, EventMsg:'test event for log4j size 2}", new Date()); size += jsonMsg.length(); logger.info(jsonMsg); msgs.add(jsonMsg); @@ -202,7 +202,7 @@ public void sendBatchedEventsByBatchsize() throws Exception { Thread.sleep(6000); TestUtil.verifyNoEventSentToSplunk(msgs); - jsonMsg = String.format("{EventDate:%s, EventMsg:'test event for log4j size 3, adding more msg to exceed the maxsize}", new Date().toString()); + jsonMsg = String.format("{EventDate:%s, EventMsg:'test event for log4j size 3, adding more msg to exceed the maxsize}", new Date()); while (size + jsonMsg.length() < 550) { jsonMsg = String.format("%saaaaa", jsonMsg); } @@ -222,12 +222,10 @@ public void errorHandlingInvalidToken() throws Exception { errors.clear(); logEx.clear(); //define error callback - HttpEventCollectorErrorHandler.onError(new HttpEventCollectorErrorHandler.ErrorCallback() { - public void error(final List data, final Exception ex) { - synchronized (errors) { - errors.add(data); - logEx.add((HttpEventCollectorErrorHandler.ServerErrorException) ex); - } + HttpEventCollectorErrorHandler.onError((data, ex) -> { + synchronized (errors) { + errors.add(data); + logEx.add(ex); } }); @@ -235,7 +233,7 @@ public void error(final List data, final Exception httpEventCollectorName = "wrongtoken"; String token = TestUtil.createHttpEventCollectorToken(httpEventCollectorName); String loggerName = "errorHandlingInvalidTokenLog4j"; - HashMap userInputs = new HashMap(); + HashMap userInputs = new HashMap<>(); userInputs.put("user_logger_name", loggerName); userInputs.put("user_httpEventCollector_token", token); LoggerContext context = TestUtil.resetLog4j2Configuration("log4j2_template.xml", "log4j2.xml", userInputs); @@ -244,14 +242,14 @@ public void error(final List data, final Exception //disable the token so that it becomes invalid TestUtil.disableHttpEventCollector(httpEventCollectorName); Thread.sleep(5000); - String jsonMsg = String.format("{EventDate:%s, EventMsg:'test event disabled token }", new Date().toString()); + String jsonMsg = String.format("{EventDate:%s, EventMsg:'test event disabled token }", new Date()); logger.info(jsonMsg); Thread.sleep(5000); //delete the token so that it becomes invalid TestUtil.deleteHttpEventCollectorToken(httpEventCollectorName); Thread.sleep(5000); - jsonMsg = String.format("{EventDate:%s, EventMsg:'test event deleted token}", new Date().toString()); + jsonMsg = String.format("{EventDate:%s, EventMsg:'test event deleted token}", new Date()); logger.info(jsonMsg); //wait for async process to return the error @@ -262,9 +260,6 @@ public void error(final List data, final Exception Thread.sleep(1000); } - if (logEx == null) - Assert.fail("didn't catch errors"); - for (List infos : errors) { for (HttpEventCollectorEventInfo info : infos) { System.out.println(info.getMessage()); @@ -272,10 +267,15 @@ public void error(final List data, final Exception } System.out.println("======print logEx"); - System.out.println(logEx.toString()); + System.out.println(logEx); System.out.println("======finish print logEx"); - Assert.assertEquals("Invalid token", logEx.get(1).getErrorText()); - Assert.assertEquals(4, logEx.get(1).getErrorCode()); + // in this case expect a valid http reply with a json error message + HttpEventCollectorErrorHandler.ServerErrorException serverErrorException1 = (HttpEventCollectorErrorHandler.ServerErrorException) logEx.get(0); + Assert.assertEquals("Token disabled", serverErrorException1.getErrorText()); + Assert.assertEquals(1, serverErrorException1.getErrorCode()); + HttpEventCollectorErrorHandler.ServerErrorException serverErrorException2 = (HttpEventCollectorErrorHandler.ServerErrorException) logEx.get(1); + Assert.assertEquals("Invalid token", serverErrorException2.getErrorText()); + Assert.assertEquals(4, serverErrorException2.getErrorCode()); Assert.assertEquals(2, errors.size()); @@ -291,12 +291,10 @@ public void errorHandlingDisabledHttpEventCollectorEndpoint() throws Exception { logEx.clear(); //define error callback - HttpEventCollectorErrorHandler.onError(new HttpEventCollectorErrorHandler.ErrorCallback() { - public void error(final List data, final Exception ex) { - synchronized (errors) { - errors.add(data); - logEx.add((HttpEventCollectorErrorHandler.ServerErrorException) ex); - } + HttpEventCollectorErrorHandler.onError((data, ex) -> { + synchronized (errors) { + errors.add(data); + logEx.add(ex); } }); @@ -304,7 +302,7 @@ public void error(final List data, final Exception httpEventCollectorName = "wrongtoken"; String token = TestUtil.createHttpEventCollectorToken(httpEventCollectorName); String loggerName = "errorHandlingDisabledHttpEventCollectorEndpoint"; - HashMap userInputs = new HashMap(); + HashMap userInputs = new HashMap<>(); userInputs.put("user_logger_name", loggerName); userInputs.put("user_httpEventCollector_token", token); LoggerContext context = TestUtil.resetLog4j2Configuration("log4j2_template.xml", "log4j2.xml", userInputs); @@ -314,7 +312,7 @@ public void error(final List data, final Exception //disable httpEventCollector endpoint TestUtil.disableHttpEventCollector(); Thread.sleep(1000); - String jsonMsg = String.format("{EventDate:%s, EventMsg:'test event httpEventCollector disabled}", new Date().toString()); + String jsonMsg = String.format("{EventDate:%s, EventMsg:'test event httpEventCollector disabled}", new Date()); logger.info(jsonMsg); //wait for async process to return the error @@ -325,13 +323,11 @@ public void error(final List data, final Exception Thread.sleep(1000); } - if (logEx == null) - Assert.fail("didn't catch errors"); Assert.assertTrue(errors.size() >= 1); - System.out.println(logEx.toString()); + System.out.println(logEx); if (!StringUtils.containsAny(logEx.toString(), "Failed to connect to", "Remote host terminated the handshake", "Connection reset")) - Assert.fail(String.format("Unexpected error message '%s'", logEx.toString())); + Assert.fail(String.format("Unexpected error message '%s'", logEx)); } /** @@ -345,7 +341,7 @@ public void eventsIsIndexedInOrderOfSent() throws Exception { TestUtil.createIndex(indexName); String token = TestUtil.createHttpEventCollectorToken(httpEventCollectorName); String loggerName = "splunkLogger4j2OrderOfSent"; - HashMap userInputs = new HashMap(); + HashMap userInputs = new HashMap<>(); userInputs.put("user_logger_name", loggerName); userInputs.put("user_httpEventCollector_token", token); userInputs.put("user_index", indexName); @@ -354,8 +350,7 @@ public void eventsIsIndexedInOrderOfSent() throws Exception { org.apache.logging.log4j.core.LoggerContext context = TestUtil.resetLog4j2Configuration("log4j2_template.xml", "log4j2.xml", userInputs); //send multiple events and verify they are indexed in the order of sending - List msgs = new ArrayList(); - Date date = new Date(); + List msgs = new ArrayList<>(); int totalEventsCount = 1000; Logger logger = context.getLogger(loggerName); String prefix="log4j2 multiple events"; @@ -386,8 +381,7 @@ public void canSendJsonEventUsingUtilLoggerWithJsonSourceType() throws Exception public void canSendJsonEventUsingUtilLoggerWithDefaultSourceType() throws Exception { canSendJsonEventUsingUtilLoggerWithSourceType("battlecat_test"); } - - @SuppressWarnings("unchecked") + private void canSendJsonEventUsingUtilLoggerWithSourceType(final String sourceType) throws Exception { final String token = TestUtil.createHttpEventCollectorToken(httpEventCollectorName); @@ -400,7 +394,7 @@ private void canSendJsonEventUsingUtilLoggerWithSourceType(final String sourceTy final Logger logger = context.getLogger(loggerName); - final List msgs = new ArrayList(); + final List msgs = new ArrayList<>(); final long timeMillsec = new Date().getTime(); diff --git a/src/test/java/HttpEventCollector_LogbackTest.java b/src/test/java/HttpEventCollector_LogbackTest.java index 3fa2c20e..e0adc50a 100644 --- a/src/test/java/HttpEventCollector_LogbackTest.java +++ b/src/test/java/HttpEventCollector_LogbackTest.java @@ -14,6 +14,7 @@ * under the License. */ +import java.rmi.server.ExportException; import java.util.*; import com.google.gson.JsonObject; @@ -30,8 +31,8 @@ public final class HttpEventCollector_LogbackTest { private String httpEventCollectorName = "LogbackTest"; - List> errors = new ArrayList>(); - List logEx = new ArrayList(); + List> errors = new ArrayList<>(); + List logEx = new ArrayList<>(); /** * sending a message via httplogging using logback to splunk @@ -260,8 +261,10 @@ public void error(final List data, final Exception System.out.println("======print logEx"); System.out.println(logEx.toString()); System.out.println("======finish print logEx"); - Assert.assertEquals("Invalid token", logEx.get(1).getErrorText()); - Assert.assertEquals(4, logEx.get(1).getErrorCode()); + // in this case expect a valid http reply with a json error message + HttpEventCollectorErrorHandler.ServerErrorException serverErrorException = (HttpEventCollectorErrorHandler.ServerErrorException) logEx.get(1); + Assert.assertEquals("Invalid token", serverErrorException.getErrorText()); + Assert.assertEquals(4, serverErrorException.getErrorCode()); for (List infos : errors) { @@ -286,7 +289,7 @@ public void errorHandlingDisabledHttpEventCollectorEndpoint() throws Exception { public void error(final List data, final Exception ex) { synchronized (errors) { errors.add(data); - logEx.add((HttpEventCollectorErrorHandler.ServerErrorException) ex); + logEx.add(ex); } } }); diff --git a/src/test/java/HttpEventCollector_Test.java b/src/test/java/HttpEventCollector_Test.java index 35a32920..7d76ead7 100644 --- a/src/test/java/HttpEventCollector_Test.java +++ b/src/test/java/HttpEventCollector_Test.java @@ -200,13 +200,11 @@ private boolean insertDataWithLoggerAndVerify(String token, String loggerType, i } private void LogToSplunk(boolean batching) throws Exception { - HttpEventCollectorErrorHandler.onError(new HttpEventCollectorErrorHandler.ErrorCallback() { - public void error(final List data, final Exception ex) { - HttpEventCollectorErrorHandler.ServerErrorException serverErrorException = - (HttpEventCollectorErrorHandler.ServerErrorException) ex; - System.out.printf("ERROR: %s", ex.toString()); - Assert.assertTrue(false); - } + HttpEventCollectorErrorHandler.onError((data, ex) -> { + HttpEventCollectorErrorHandler.ServerErrorException serverErrorException = + (HttpEventCollectorErrorHandler.ServerErrorException) ex; + System.out.printf("ERROR: %s", ex.toString()); + Assert.assertTrue(false); }); int expectedCounter = 2; System.out.printf("\tSetting up http event collector with %s ... ", batching ? "batching" : "no batching"); @@ -265,13 +263,11 @@ public void run() { @Test public void ResendDataToSplunk() throws Exception { - HttpEventCollectorErrorHandler.onError(new HttpEventCollectorErrorHandler.ErrorCallback() { - public void error(final List data, final Exception ex) { - HttpEventCollectorErrorHandler.ServerErrorException serverErrorException = - (HttpEventCollectorErrorHandler.ServerErrorException) ex; - System.out.printf("ERROR: %s", ex.toString()); - Assert.assertTrue(false); - } + HttpEventCollectorErrorHandler.onError((data, ex) -> { + HttpEventCollectorErrorHandler.ServerErrorException serverErrorException = + (HttpEventCollectorErrorHandler.ServerErrorException) ex; + System.out.printf("ERROR: %s", ex.toString()); + Assert.assertTrue(false); }); boolean batching = false; System.out.printf("\tSetting up http event collector with %s ... ", batching ? "batching" : "no batching"); diff --git a/src/test/java/com/splunk/logging/HttpEventCollectorErrorHandlerTest.java b/src/test/java/com/splunk/logging/HttpEventCollectorErrorHandlerTest.java new file mode 100644 index 00000000..f5d151a8 --- /dev/null +++ b/src/test/java/com/splunk/logging/HttpEventCollectorErrorHandlerTest.java @@ -0,0 +1,90 @@ +package com.splunk.logging; + +import com.splunk.logging.util.StandardErrorCallback; +import junit.framework.TestCase; +import org.jetbrains.annotations.NotNull; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class HttpEventCollectorErrorHandlerTest extends TestCase { + + @Override + protected void setUp() throws Exception { + super.setUp(); + // reset error handler for each test + HttpEventCollectorErrorHandler.onError(null); + } + + public void testRegisterClassName() { + // should not throw exceptions + HttpEventCollectorErrorHandler.registerClassName(null); + HttpEventCollectorErrorHandler.registerClassName(""); + HttpEventCollectorErrorHandler.registerClassName("NonExistentClass"); + HttpEventCollectorErrorHandler.registerClassName("com.splunk.logging.util.StandardErrorCallback"); + HttpEventCollectorErrorHandler.registerClassName("com.splunk.logging.util.StandardErrorCallback"); + } + + public void testOnErrorDoubleRegisterAndCounters() { + StandardErrorCallback standardErrorCallback = new StandardErrorCallback(); + // double register should be ok + HttpEventCollectorErrorHandler.onError(standardErrorCallback); + HttpEventCollectorErrorHandler.onError(standardErrorCallback); + + HttpEventCollectorErrorHandler.error(createHttpEventCollectorEventInfos(), new RuntimeException("test")); + + assertEquals(1, standardErrorCallback.getErrorCount()); + assertEquals(2, standardErrorCallback.getEventCount()); + } + + public void testOnErrorCounters() { + StandardErrorCallback standardErrorCallback = new StandardErrorCallback(); + HttpEventCollectorErrorHandler.onError(standardErrorCallback); + + HttpEventCollectorErrorHandler.error(createHttpEventCollectorEventInfos(), new RuntimeException("test")); + + assertEquals(1, standardErrorCallback.getErrorCount()); + assertEquals(2, standardErrorCallback.getEventCount()); + + standardErrorCallback.resetCounters(); + + assertEquals(0, standardErrorCallback.getErrorCount()); + assertEquals(0, standardErrorCallback.getEventCount()); + } + + public void testError() { + HttpEventCollectorErrorHandler.error(null, null); + + HttpEventCollectorErrorHandler.onError((data, exception) -> { + assertNull(data); + assertNull(exception); + }); + + HttpEventCollectorErrorHandler.error(null, null); + + HttpEventCollectorErrorHandler.onError((data, exception) -> { + assertTrue(exception.getMessage().contains("test exception")); + assertEquals(2, data.size()); + assertEquals("FATAL", data.get(0).getSeverity()); + }); + + List data = createHttpEventCollectorEventInfos(); + + HttpEventCollectorErrorHandler.error(data, new IllegalArgumentException("test exception")); + + HttpEventCollectorErrorHandler.error(data, new HttpEventCollectorErrorHandler.ServerErrorException("{ 'text':'test exception', 'code':4}")); + + } + + @NotNull + private List createHttpEventCollectorEventInfos() { + List data = new ArrayList<>(); + Map map = new HashMap<>(); + map.put("name", "value"); + data.add(new HttpEventCollectorEventInfo(0, "FATAL", "message", "logger-name", "thread-name", map, "exception-message", "marker")); + data.add(new HttpEventCollectorEventInfo(1, "INFO", "message", "logger-name", "thread-name", map, "exception-message", "marker")); + return data; + } +} \ No newline at end of file diff --git a/src/test/resources/log4j2_template.xml b/src/test/resources/log4j2_template.xml index 8b04588c..edccc300 100644 --- a/src/test/resources/log4j2_template.xml +++ b/src/test/resources/log4j2_template.xml @@ -18,6 +18,7 @@ middleware="%user_middleware%" eventBodySerializer="%user_eventBodySerializer%" eventHeaderSerializer="%user_eventHeaderSerializer%" + errorCallback="%user_errorCallback%" > diff --git a/src/test/resources/logback_template.xml b/src/test/resources/logback_template.xml index c8719385..ab44dded 100644 --- a/src/test/resources/logback_template.xml +++ b/src/test/resources/logback_template.xml @@ -18,6 +18,7 @@ %user_middleware% %user_eventBodySerializer% %user_eventHeaderSerializer% + %user_errorCallback% %msg diff --git a/src/test/resources/logging_template.properties b/src/test/resources/logging_template.properties index 30e37ba1..066e0c95 100644 --- a/src/test/resources/logging_template.properties +++ b/src/test/resources/logging_template.properties @@ -22,6 +22,7 @@ com.splunk.logging.HttpEventCollectorLoggingHandler.retries_on_error = %user_ret com.splunk.logging.HttpEventCollectorLoggingHandler.eventBodySerializer = %user_eventBodySerializer% com.splunk.logging.HttpEventCollectorLoggingHandler.eventHeaderSerializer = %user_eventHeaderSerializer% +com.splunk.logging.HttpEventCollectorLoggingHandler.errorCallback = %user_errorCallback% # You would usually use XMLFormatter or SimpleFormatter for this property, but # SimpleFormatter doesn't accept a format string under Java 6, and so we cannot From 256fc35520f005d938eda5b4bfb960c280a51580 Mon Sep 17 00:00:00 2001 From: Peter Paul Bakker Date: Wed, 9 Mar 2022 23:05:57 +0100 Subject: [PATCH 2/2] revert changes in changelog and readme --- CHANGELOG.md | 4 ---- README.md | 8 +++----- 2 files changed, 3 insertions(+), 9 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8373983e..443daabf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,9 +1,5 @@ # Splunk Logging for Java Changelog -## Version 1.12.0 - -* Added StandardErrorCallback. Register ErrorCallback implementations via logback or log4j xml config. (@stokpop) - ## Version 1.11.4 ### Critical Security Update diff --git a/README.md b/README.md index 7545ae0d..18149ac1 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Splunk Logging for Java -#### Version 1.12.0 +#### Version 1.11.4 Splunk logging for Java enables you to log events to HTTP Event Collector or to a TCP input on a Splunk Enterprise instance within your Java applications. You can use three major Java logging frameworks: [Logback](http://logback.qos.ch), [Log4j 2](http://logging.apache.org/log4j/2.x/), and [java.util.logging](https://docs.oracle.com/javase/7/docs/api/java/util/logging/package-summary.html). Splunk logging for Java is also enabled for [Simple Logging Facade for Java (SLF4J)](http://www.slf4j.org). @@ -11,8 +11,6 @@ Splunk logging for Java provides: * Handler classes that export the logging events. * An optional error handler to catch failures for HTTP Event Collector events. - * Use `com.splunk.logging.util.StandardErrorCallback` to write errors to standard out. - * Use the `errorCallback` field in logging configs to register a ErrorCallback class. * Example configuration files for all three frameworks that show how to configure the frameworks to write to HTTP Event Collector or TCP ports. @@ -28,7 +26,7 @@ If you haven't already installed Splunk, download it [here](http://www.splunk.com/download). For more about installing and running Splunk and system requirements, see [Installing & Running Splunk](http://dev.splunk.com/view/SP-CAAADRV). Splunk logging for Java is tested with Splunk Enterprise 8.0 and 8.2.0. -#### Java +#### Java You'll need Java version 8 or higher, from [OpenJDK](https://openjdk.java.net) or [Oracle](https://www.oracle.com/technetwork/java). @@ -80,4 +78,4 @@ You can [contact support][contact] if you have Splunk related questions. You can reach the Dev Platform team at [devinfo@splunk.com](mailto:devinfo@splunk.com). -[contact]: https://www.splunk.com/en_us/support-and-services.html +[contact]: https://www.splunk.com/en_us/support-and-services.html \ No newline at end of file