diff --git a/README.md b/README.md index 833f042..64d65cd 100644 --- a/README.md +++ b/README.md @@ -54,29 +54,29 @@ Be sure to replace [collector-url] with the URL after creating an HTTP Hosted Co 2. Sumo only supports [certain time formats](https://help.sumologic.com/03Send-Data/Sources/04Reference-Information-for-Sources/Timestamps%2C-Time-Zones%2C-Time-Ranges%2C-and-Date-Formats), and accidentally using an invalid time format could cause [message time discrepancies](https://help.sumologic.com/03Send-Data/Collector-FAQs/Troubleshooting-time-discrepancies). ### Parameters -| Parameter | Required? | Default Value | Description | -|-----------------------|----------|---------------|--------------------------------------------------------------------------------------------------------------------------------------------| -| name | Yes | | Name used to register Log4j Appender | -| url | Yes | | HTTP collection endpoint URL | -| sourceName | No | "Http Input" | Source name to appear when searching on Sumo Logic by `_sourceName` | -| sourceHost | No | Client IP Address | Source host to appear when searching on Sumo Logic by `_sourceHost` | -| sourceCategory | No | "Http Input" | Source category to appear when searching on Sumo Logic by `_sourceCategory` | -| proxyHost | No | | Proxy host IP address | -| proxyPort | No | | Proxy host port number | -| proxyAuth | No | | For basic authentication proxy, set to "basic". For NTLM authentication proxy, set to "ntlm". For no authentication proxy, do not specify. | -| proxyUser | No | | Proxy host username for basic and NTLM authentication. For no authentication proxy, do not specify. | -| proxyPassword | No | | Proxy host password for basic and NTLM authentication. For no authentication proxy, do not specify. | -| proxyDomain | No | | Proxy host domain name for NTLM authentication only | -| retryInterval | No | 10000 | Retry interval (in ms) if a request fails | -| maxNumberOfRetries | No | -1 | Maximum number of retries before a message is dropped. Negative values represent no limit on retries. | -| connectionTimeout | No | 1000 | Timeout (in ms) for connection | -| socketTimeout | No | 60000 | Timeout (in ms) for a socket | -| messagesPerRequest | No | 100 | Number of messages needed to be in the queue before flushing | -| maxFlushInterval | No | 10000 | Maximum interval (in ms) between flushes | -| flushingAccuracy | No | 250 | How often (in ms) that the flushing thread checks the message queue | -| maxQueueSizeBytes | No | 1000000 | Maximum capacity (in bytes) of the message queue -| flushAllBeforeStopping| No | false | Flush all messages before stopping regardless of flushingAccuracy -| retryableHttpCodeRegex| No | ^5.* | Regular expression specifying which HTTP error code(s) should be retried during sending. By default, all 5xx error codes will be retried. +| Parameter | Required? | Default Value | Description | +|------------------------|-----------|-------------------|--------------------------------------------------------------------------------------------------------------------------------------------| +| name | Yes | | Name used to register Log4j Appender | +| url | Yes | | HTTP collection endpoint URL | +| sourceName | No | "Http Input" | Source name to appear when searching on Sumo Logic by `_sourceName` | +| sourceHost | No | Client IP Address | Source host to appear when searching on Sumo Logic by `_sourceHost` | +| sourceCategory | No | "Http Input" | Source category to appear when searching on Sumo Logic by `_sourceCategory` | +| proxyHost | No | | Proxy host IP address | +| proxyPort | No | | Proxy host port number | +| proxyAuth | No | | For basic authentication proxy, set to "basic". For NTLM authentication proxy, set to "ntlm". For no authentication proxy, do not specify. | +| proxyUser | No | | Proxy host username for basic and NTLM authentication. For no authentication proxy, do not specify. | +| proxyPassword | No | | Proxy host password for basic and NTLM authentication. For no authentication proxy, do not specify. | +| proxyDomain | No | | Proxy host domain name for NTLM authentication only | +| retryInterval | No | 10000 | Retry interval (in ms) if a request fails | +| maxNumberOfRetries | No | -1 | Maximum number of retries before a message is dropped. Negative values represent no limit on retries. | +| connectionTimeout | No | 1000 | Timeout (in ms) for connection | +| socketTimeout | No | 60000 | Timeout (in ms) for a socket | +| messagesPerRequest | No | 100 | Number of messages needed to be in the queue before flushing | +| maxFlushInterval | No | 10000 | Maximum interval (in ms) between flushes | +| flushingAccuracy | No | 250 | How often (in ms) that the flushing thread checks the message queue | +| maxQueueSizeBytes | No | 1000000 | Maximum capacity (in bytes) of the message queue | +| flushAllBeforeStopping | No | false | Flush all messages before stopping regardless of flushingAccuracy | +| retryableHttpCodeRegex | No | ^5.* | Regular expression specifying which HTTP error code(s) should be retried during sending. By default, all 5xx error codes will be retried. | #### Example with Optional Parameters `log4j2.xml`: diff --git a/src/test/java/com/sumologic/log4j/SumoLogicAppenderTest.java b/src/test/java/com/sumologic/log4j/SumoLogicAppenderTest.java index 34448fc..0e4a394 100644 --- a/src/test/java/com/sumologic/log4j/SumoLogicAppenderTest.java +++ b/src/test/java/com/sumologic/log4j/SumoLogicAppenderTest.java @@ -28,18 +28,24 @@ import com.sumologic.log4j.server.AggregatingHttpHandler; import com.sumologic.log4j.server.MaterializedHttpRequest; import com.sumologic.log4j.server.MockHttpServer; +import org.apache.logging.log4j.core.layout.PatternLayout; import org.junit.After; import org.junit.Before; import org.junit.Test; import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.LogManager; +import java.util.concurrent.TimeUnit; + import static org.junit.Assert.*; public class SumoLogicAppenderTest { private static final int PORT = 26932; + private static final String testLocalhostUrl = "http://localhost:8080"; + private static final String testAppenderName = "TestAppender"; + private MockHttpServer server; private AggregatingHttpHandler handler; @@ -51,7 +57,7 @@ public void setUp() throws Exception { } @After - public void tearDown() throws Exception { + public void tearDown() { if (server != null) { server.stop(); } @@ -61,28 +67,28 @@ public void tearDown() throws Exception { public void testMessagesWithMetadata() throws Exception { // See ./resources/log4j2.xml for definition Logger loggerInTest = LogManager.getLogger("TestAppender1"); - StringBuffer expected = new StringBuffer(); + StringBuilder expected = new StringBuilder(); for (int i = 0; i < 100; i ++) { String message = "info" + i; loggerInTest.info(message); - expected.append("[main] INFO TestAppender1 - " + message + "\n"); + expected.append("[main] INFO TestAppender1 - ").append(message).append(System.lineSeparator()); } Thread.sleep(300); // Check headers for(MaterializedHttpRequest request: handler.getExchanges()) { - assertEquals(true, request.getHeaders().getFirst("X-Sumo-Name").equals("mySource")); - assertEquals(true, request.getHeaders().getFirst("X-Sumo-Category").equals("myCategory")); - assertEquals(true, request.getHeaders().getFirst("X-Sumo-Host").equals("myHost")); + assertEquals("mySource", request.getHeaders().getFirst("X-Sumo-Name")); + assertEquals("myCategory", request.getHeaders().getFirst("X-Sumo-Category")); + assertEquals("myHost", request.getHeaders().getFirst("X-Sumo-Host")); assertEquals("log4j2-appender", request.getHeaders().getFirst("X-Sumo-Client")); } // Check body - StringBuffer actual = new StringBuffer(); + StringBuilder actual = new StringBuilder(); for(MaterializedHttpRequest request: handler.getExchanges()) { for (String line : request.getBody().split(System.lineSeparator())) { // Strip timestamp int mainStart = line.indexOf("[main]"); String trimmed = line.substring(mainStart); - actual.append(trimmed + "\n"); + actual.append(trimmed).append(System.lineSeparator()); } } assertEquals(expected.toString(), actual.toString()); @@ -99,9 +105,9 @@ public void testMessagesWithoutMetadata() throws Exception { } assertEquals(numMessages, handler.getExchanges().size()); for(MaterializedHttpRequest request: handler.getExchanges()) { - assertEquals(true, request.getHeaders().getFirst("X-Sumo-Name") == null); - assertEquals(true, request.getHeaders().getFirst("X-Sumo-Category") == null); - assertEquals(true, request.getHeaders().getFirst("X-Sumo-Host") == null); + assertNull(request.getHeaders().getFirst("X-Sumo-Name")); + assertNull(request.getHeaders().getFirst("X-Sumo-Category")); + assertNull(request.getHeaders().getFirst("X-Sumo-Host")); assertEquals("log4j2-appender", request.getHeaders().getFirst("X-Sumo-Client")); } } @@ -111,4 +117,54 @@ public void setupAppenderWithoutRequiredFields() { SumoLogicAppender appender = SumoLogicAppender.newBuilder().build(); assertNull(appender); } + + @Test + public void buildAppenderWithoutRequiredFieldUrl() { + SumoLogicAppender appender = SumoLogicAppender.newBuilder().setName(testAppenderName).build(); + assertNull(appender); + } + + @Test + public void buildAppenderWithoutRequiredFieldName() { + SumoLogicAppender appender = SumoLogicAppender.newBuilder().setUrl(testLocalhostUrl).build(); + assertNull(appender); + } + + @Test + public void buildAppenderWithRequiredFieldsOnlyAndStop(){ + SumoLogicAppender appender = SumoLogicAppender.newBuilder() + .setName(testAppenderName) + .setUrl(testLocalhostUrl) + .build(); + assertNotNull(appender); + assertTrue(appender.stop(1L, TimeUnit.SECONDS)); + } + + @Test + public void buildAppenderWithRequiredFieldsAndFieldsWithUserDefinedDefaultOrNullAndStop(){ + SumoLogicAppender appender = SumoLogicAppender.newBuilder() + .setName(testAppenderName) + .setUrl(testLocalhostUrl) + .setRetryInterval(10000) + .setMaxNumberOfRetries(-1) + .setConnectionTimeout(1000) + .setSocketTimeout(60000) + .setMessagesPerRequest(1) + .setMaxFlushInterval(10000) + .setFlushingAccuracy(250) + .setMaxQueueSizeBytes(1000000) + .setFlushAllBeforeStopping(false) + .setRetryableHttpCodeRegex("^5.*") + .setLayout(PatternLayout.createDefaultLayout()) + .setSourceName("testSource") + .setSourceCategory("testCategory") + .setSourceHost("testHost") + .setFilter(null) + .setLayout(null) + .build(); + assertNotNull(appender); + assertEquals(appender.getName(), testAppenderName); + assertNull(appender.getFilter()); + assertTrue(appender.stop(1L, TimeUnit.SECONDS)); + } }