Repository: logging-log4j2 Updated Branches: refs/heads/LOG4J2-1442 fd1d7ea20 -> 7f9f60be1
LOG4J2-1442 Unit tests Project: http://git-wip-us.apache.org/repos/asf/logging-log4j2/repo Commit: http://git-wip-us.apache.org/repos/asf/logging-log4j2/commit/7f9f60be Tree: http://git-wip-us.apache.org/repos/asf/logging-log4j2/tree/7f9f60be Diff: http://git-wip-us.apache.org/repos/asf/logging-log4j2/diff/7f9f60be Branch: refs/heads/LOG4J2-1442 Commit: 7f9f60be12d85ef85e6448ccd3794c26ab041aea Parents: fd1d7ea Author: Mikael Ståldal <[email protected]> Authored: Tue May 9 17:40:15 2017 +0200 Committer: Mikael Ståldal <[email protected]> Committed: Tue May 9 17:40:15 2017 +0200 ---------------------------------------------------------------------- log4j-core/pom.xml | 6 + .../core/appender/HttpURLConnectionManager.java | 35 ++++- .../log4j/core/appender/HttpAppenderTest.java | 152 ++++++++++++++++++- .../src/test/resources/HttpAppenderTest.xml | 26 +--- pom.xml | 7 + 5 files changed, 197 insertions(+), 29 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/7f9f60be/log4j-core/pom.xml ---------------------------------------------------------------------- diff --git a/log4j-core/pom.xml b/log4j-core/pom.xml index 7881cc4..f98b03e 100644 --- a/log4j-core/pom.xml +++ b/log4j-core/pom.xml @@ -324,6 +324,12 @@ <version>2.4.7</version> <scope>test</scope> </dependency> + <!-- Used for testing HttpAppender --> + <dependency> + <groupId>com.github.tomakehurst</groupId> + <artifactId>wiremock</artifactId> + <scope>test</scope> + </dependency> <!-- GC-free --> <dependency> <groupId>com.google.code.java-allocation-instrumenter</groupId> http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/7f9f60be/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/HttpURLConnectionManager.java ---------------------------------------------------------------------- diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/HttpURLConnectionManager.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/HttpURLConnectionManager.java index 357c5b7..d656c90 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/HttpURLConnectionManager.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/HttpURLConnectionManager.java @@ -18,10 +18,12 @@ package org.apache.logging.log4j.core.appender; import java.io.IOException; +import java.io.InputStream; import java.io.OutputStream; import java.net.HttpURLConnection; import java.net.MalformedURLException; import java.net.URL; +import java.nio.charset.Charset; import java.util.Objects; import org.apache.logging.log4j.core.Layout; @@ -30,9 +32,12 @@ import org.apache.logging.log4j.core.LoggerContext; import org.apache.logging.log4j.core.config.Configuration; import org.apache.logging.log4j.core.config.ConfigurationException; import org.apache.logging.log4j.core.config.Property; +import org.apache.logging.log4j.core.util.IOUtils; public class HttpURLConnectionManager extends HttpManager { + private static final Charset CHARSET = Charset.forName("US-ASCII"); + private final URL url; private final String method; private final int connectTimeoutMillis; @@ -69,13 +74,41 @@ public class HttpURLConnectionManager extends HttpManager { header.getName(), header.isValueNeedsLookup() ? getConfiguration().getStrSubstitutor().replace(event, header.getValue()) : header.getValue()); } + byte[] msg = layout.toByteArray(event); urlConnection.setFixedLengthStreamingMode(msg.length); urlConnection.connect(); try (OutputStream os = urlConnection.getOutputStream()) { os.write(msg); } - urlConnection.getInputStream().close(); + + byte[] buffer = new byte[1024]; + InputStream is = null; + try { + is = urlConnection.getInputStream(); + while (IOUtils.EOF != is.read(buffer)); + } catch (IOException e) { + StringBuilder errorMessage = new StringBuilder(); + try (InputStream es = urlConnection.getErrorStream()) { + errorMessage.append(urlConnection.getResponseCode()); + if (urlConnection.getResponseMessage() != null) { + errorMessage.append(' ').append(urlConnection.getResponseMessage()); + } + if (es != null) { + errorMessage.append(" - "); + int n; + while (IOUtils.EOF != (n = es.read(buffer))) { + errorMessage.append(new String(buffer, 0, n, CHARSET)); + } + } + } + if (urlConnection.getResponseCode() > -1) + throw new IOException(errorMessage.toString()); + else + throw e; + } finally { + if (is != null) is.close(); + } } } http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/7f9f60be/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/HttpAppenderTest.java ---------------------------------------------------------------------- diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/HttpAppenderTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/HttpAppenderTest.java index 98120a1..c9f9385 100644 --- a/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/HttpAppenderTest.java +++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/HttpAppenderTest.java @@ -1,14 +1,28 @@ package org.apache.logging.log4j.core.appender; +import java.io.IOException; + +import com.github.tomakehurst.wiremock.client.ResponseDefinitionBuilder; +import com.github.tomakehurst.wiremock.junit.WireMockRule; import org.apache.logging.log4j.Level; import org.apache.logging.log4j.core.Appender; +import org.apache.logging.log4j.core.config.Property; import org.apache.logging.log4j.core.impl.Log4jLogEvent; +import org.apache.logging.log4j.core.layout.JsonLayout; +import org.apache.logging.log4j.core.lookup.JavaLookup; import org.apache.logging.log4j.junit.LoggerContextRule; import org.apache.logging.log4j.message.SimpleMessage; +import org.apache.logging.log4j.status.StatusData; +import org.apache.logging.log4j.status.StatusListener; +import org.apache.logging.log4j.status.StatusLogger; import org.junit.Rule; import org.junit.Test; -// TODO this test requires manual verification +import static org.junit.Assert.*; +import static com.github.tomakehurst.wiremock.client.WireMock.*; +import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.wireMockConfig; + +// TODO test HTTPS public class HttpAppenderTest { private static final String LOG_MESSAGE = "Hello, world!"; @@ -22,30 +36,152 @@ public class HttpAppenderTest { .build(); } + private final ResponseDefinitionBuilder SUCCESS_RESPONSE = aResponse().withStatus(201) + .withHeader("Content-Type", "application/json") + .withBody("{\"status\":\"created\"}"); + + private final ResponseDefinitionBuilder FAILURE_RESPONSE = aResponse().withStatus(400) + .withHeader("Content-Type", "application/json") + .withBody("{\"status\":\"error\"}"); + + private final JavaLookup JAVA_LOOKUP = new JavaLookup(); + @Rule public LoggerContextRule ctx = new LoggerContextRule("HttpAppenderTest.xml"); + @Rule + public WireMockRule wireMockRule = new WireMockRule(wireMockConfig().dynamicPort()); + + @Test + public void testAppend() throws Exception { + wireMockRule.stubFor(post(urlEqualTo("/test/log4j/")) + .willReturn(SUCCESS_RESPONSE)); + + final Appender appender = HttpAppender.newBuilder() + .withName("Http") + .withLayout(JsonLayout.createDefaultLayout()) + .setConfiguration(ctx.getConfiguration()) + .setUrl("http://localhost:"+wireMockRule.port()+"/test/log4j/") + .build(); + appender.append(createLogEvent()); + + wireMockRule.verify(postRequestedFor(urlEqualTo("/test/log4j/")) + .withHeader("Host", containing("localhost")) + .withHeader("Content-Type", containing("application/json")) + .withRequestBody(containing("\"message\" : \"" + LOG_MESSAGE + "\""))); + } + + @Test + public void testAppendMethodPut() throws Exception { + wireMockRule.stubFor(put(urlEqualTo("/test/log4j/1234")) + .willReturn(SUCCESS_RESPONSE)); + + final Appender appender = HttpAppender.newBuilder() + .withName("Http") + .withLayout(JsonLayout.createDefaultLayout()) + .setConfiguration(ctx.getConfiguration()) + .setMethod("PUT") + .setUrl("http://localhost:"+wireMockRule.port()+"/test/log4j/1234") + .build(); + appender.append(createLogEvent()); + + wireMockRule.verify(putRequestedFor(urlEqualTo("/test/log4j/1234")) + .withHeader("Host", containing("localhost")) + .withHeader("Content-Type", containing("application/json")) + .withRequestBody(containing("\"message\" : \"" + LOG_MESSAGE + "\""))); + } + @Test - public void testAppendSuccess() throws Exception { - final Appender appender = ctx.getRequiredAppender("HttpSuccess"); + public void testAppendCustomHeader() throws Exception { + wireMockRule.stubFor(post(urlEqualTo("/test/log4j/")) + .willReturn(SUCCESS_RESPONSE)); + + final Appender appender = HttpAppender.newBuilder() + .withName("Http") + .withLayout(JsonLayout.createDefaultLayout()) + .setConfiguration(ctx.getConfiguration()) + .setUrl("http://localhost:"+wireMockRule.port()+"/test/log4j/") + .setHeaders(new Property[] { + Property.createProperty("X-Test", "header value"), + Property.createProperty("X-Runtime", "${java:runtime}") + }) + .build(); appender.append(createLogEvent()); + + wireMockRule.verify(postRequestedFor(urlEqualTo("/test/log4j/")) + .withHeader("Host", containing("localhost")) + .withHeader("X-Test", equalTo("header value")) + .withHeader("X-Runtime", equalTo(JAVA_LOOKUP.getRuntime())) + .withHeader("Content-Type", containing("application/json")) + .withRequestBody(containing("\"message\" : \"" + LOG_MESSAGE + "\""))); } + volatile StatusData error; + @Test public void testAppendErrorIgnore() throws Exception { - final Appender appender = ctx.getRequiredAppender("HttpErrorIgnore"); + wireMockRule.stubFor(post(urlEqualTo("/test/log4j/")) + .willReturn(FAILURE_RESPONSE)); + + StatusLogger.getLogger().registerListener(new StatusListener() { + @Override + public void log(StatusData data) { + error = data; + } + + @Override + public Level getStatusLevel() { + return Level.ERROR; + } + + @Override + public void close() throws IOException { } + }); + + error = null; + + final Appender appender = HttpAppender.newBuilder() + .withName("Http") + .withLayout(JsonLayout.createDefaultLayout()) + .setConfiguration(ctx.getConfiguration()) + .setUrl("http://localhost:"+wireMockRule.port()+"/test/log4j/") + .build(); appender.append(createLogEvent()); + + wireMockRule.verify(postRequestedFor(urlEqualTo("/test/log4j/")) + .withHeader("Host", containing("localhost")) + .withHeader("Content-Type", containing("application/json")) + .withRequestBody(containing("\"message\" : \"" + LOG_MESSAGE + "\""))); + + assertNotNull(error); + assertEquals(Level.ERROR, error.getLevel()); + assertEquals("Unable to send HTTP in appender [Http]", error.getMessage().toString()); } @Test(expected = AppenderLoggingException.class) public void testAppendError() throws Exception { - final Appender appender = ctx.getRequiredAppender("HttpError"); + wireMockRule.stubFor(post(urlEqualTo("/test/log4j/")) + .willReturn(FAILURE_RESPONSE)); + + final Appender appender = HttpAppender.newBuilder() + .withName("Http") + .withLayout(JsonLayout.createDefaultLayout()) + .setConfiguration(ctx.getConfiguration()) + .withIgnoreExceptions(false) + .setUrl("http://localhost:"+wireMockRule.port()+"/test/log4j/") + .build(); appender.append(createLogEvent()); } - @Test - public void testAppendSubst() throws Exception { - final Appender appender = ctx.getRequiredAppender("HttpSubst"); + @Test(expected = AppenderLoggingException.class) + public void testAppendConnectError() throws Exception { + final Appender appender = HttpAppender.newBuilder() + .withName("Http") + .withLayout(JsonLayout.createDefaultLayout()) + .setConfiguration(ctx.getConfiguration()) + .withIgnoreExceptions(false) + .setUrl("http://localhost:"+(wireMockRule.port()+1)+"/test/log4j/") + .build(); appender.append(createLogEvent()); } http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/7f9f60be/log4j-core/src/test/resources/HttpAppenderTest.xml ---------------------------------------------------------------------- diff --git a/log4j-core/src/test/resources/HttpAppenderTest.xml b/log4j-core/src/test/resources/HttpAppenderTest.xml index 30edaa0..4521ed6 100644 --- a/log4j-core/src/test/resources/HttpAppenderTest.xml +++ b/log4j-core/src/test/resources/HttpAppenderTest.xml @@ -17,27 +17,13 @@ --> <Configuration name="HttpAppenderTest" status="WARN"> <Appenders> - <Http name="HttpSuccess" url="http://localhost:9200/test/log4j/"> - <Property name="X-Test" value="header value" /> - <JsonLayout properties="true"/> - </Http> - <Http name="HttpErrorIgnore" url="http://localhost:9200/test/log4j/" method="PUT"> - <JsonLayout properties="true"/> - </Http> - <Http name="HttpError" url="http://localhost:9200/test/log4j/" method="PUT" ignoreExceptions="false"> - <JsonLayout properties="true"/> - </Http> - <Http name="HttpSubst" url="http://localhost:9200/test/log4j/"> - <Property name="X-Test" value="$${java:runtime}" /> - <JsonLayout properties="true"/> - </Http> + <Console name="Console" target="SYSTEM_OUT"> + <PatternLayout pattern="%d [%t] %-5level: %msg%n%throwable" /> + </Console> </Appenders> <Loggers> - <Root level="info"> - <AppenderRef ref="HttpSuccess"/> - <AppenderRef ref="HttpErrorIgnore"/> - <AppenderRef ref="HttpError"/> - <AppenderRef ref="HttpSubst"/> + <Root level="WARN"> + <AppenderRef ref="Console"/> </Root> </Loggers> -</Configuration> \ No newline at end of file +</Configuration> http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/7f9f60be/pom.xml ---------------------------------------------------------------------- diff --git a/pom.xml b/pom.xml index 2ff0acd..cd0d4b1 100644 --- a/pom.xml +++ b/pom.xml @@ -751,6 +751,13 @@ <version>2.5</version> <scope>test</scope> </dependency> + <!-- Used for testing HttpAppender --> + <dependency> + <groupId>com.github.tomakehurst</groupId> + <artifactId>wiremock</artifactId> + <scope>test</scope> + <version>2.6.0</version> + </dependency> <!-- Used for compressing to formats other than zip and gz --> <dependency> <groupId>org.apache.commons</groupId>
