blob: a0b8df94e3aa88047141aa9c5ab3af47170cae71 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache license, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the license for the specific language governing permissions and
* limitations under the license.
*/
package org.apache.logging.log4j.core.appender;
import static com.github.tomakehurst.wiremock.client.WireMock.aResponse;
import static com.github.tomakehurst.wiremock.client.WireMock.containing;
import static com.github.tomakehurst.wiremock.client.WireMock.equalTo;
import static com.github.tomakehurst.wiremock.client.WireMock.post;
import static com.github.tomakehurst.wiremock.client.WireMock.postRequestedFor;
import static com.github.tomakehurst.wiremock.client.WireMock.put;
import static com.github.tomakehurst.wiremock.client.WireMock.putRequestedFor;
import static com.github.tomakehurst.wiremock.client.WireMock.urlEqualTo;
import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.wireMockConfig;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import java.io.IOException;
import java.net.URL;
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.lookup.JavaLookup;
import org.apache.logging.log4j.core.net.ssl.KeyStoreConfiguration;
import org.apache.logging.log4j.core.net.ssl.SslConfiguration;
import org.apache.logging.log4j.core.net.ssl.TestConstants;
import org.apache.logging.log4j.core.net.ssl.TrustStoreConfiguration;
import org.apache.logging.log4j.jackson.json.layout.JsonLayout;
import org.apache.logging.log4j.core.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.Ignore;
import org.junit.Rule;
import org.junit.Test;
import com.github.tomakehurst.wiremock.client.ResponseDefinitionBuilder;
import com.github.tomakehurst.wiremock.junit.WireMockRule;
@Ignore("Fails often on Windows")
/* Fails often on Windows, for example:
[ERROR] Failed to execute goal org.apache.maven.plugins:maven-surefire-plugin:2.20.1:test (default-test) on project log4j-core: There are test failures.
[ERROR]
[ERROR] Please refer to C:\vcs\git\apache\logging\logging-log4j2\log4j-core\target\surefire-reports for the individual test results.
[ERROR] Please refer to dump files (if any exist) [date]-jvmRun[N].dump, [date].dumpstream and [date]-jvmRun[N].dumpstream.
[ERROR] ExecutionException The forked VM terminated without properly saying goodbye. VM crash or System.exit called?
[ERROR] Command was cmd.exe /X /C ""C:\Program Files\Java\jdk1.8.0_152\jre\bin\java" -Xms256m -Xmx1024m -jar C:\Users\ggregory\AppData\Local\Temp\surefire22320217597495112\surefirebooter1486874613063862199.jar C:\Users\ggregory\AppData\Local\Temp\surefire22320217597495112 2018-01-23T11-03-18_847-jvmRun6 surefire6375637980242546356tmp surefire_441335531705722358735tmp"
[ERROR] Process Exit Code: 0
[ERROR] Crashed tests:
[ERROR] org.apache.logging.log4j.core.appender.HttpAppenderTest
[ERROR] org.apache.maven.surefire.booter.SurefireBooterForkException: ExecutionException The forked VM terminated without properly saying goodbye. VM crash or System.exit called?
[ERROR] Command was cmd.exe /X /C ""C:\Program Files\Java\jdk1.8.0_152\jre\bin\java" -Xms256m -Xmx1024m -jar C:\Users\ggregory\AppData\Local\Temp\surefire22320217597495112\surefirebooter1486874613063862199.jar C:\Users\ggregory\AppData\Local\Temp\surefire22320217597495112 2018-01-23T11-03-18_847-jvmRun6 surefire6375637980242546356tmp surefire_441335531705722358735tmp"
[ERROR] Process Exit Code: 0
[ERROR] Crashed tests:
[ERROR] org.apache.logging.log4j.core.appender.HttpAppenderTest
[ERROR] at org.apache.maven.plugin.surefire.booterclient.ForkStarter.awaitResultsDone(ForkStarter.java:496)
[ERROR] at org.apache.maven.plugin.surefire.booterclient.ForkStarter.runSuitesForkPerTestSet(ForkStarter.java:443)
[ERROR] at org.apache.maven.plugin.surefire.booterclient.ForkStarter.run(ForkStarter.java:295)
[ERROR] at org.apache.maven.plugin.surefire.booterclient.ForkStarter.run(ForkStarter.java:246)
[ERROR] at org.apache.maven.plugin.surefire.AbstractSurefireMojo.executeProvider(AbstractSurefireMojo.java:1124)
[ERROR] at org.apache.maven.plugin.surefire.AbstractSurefireMojo.executeAfterPreconditionsChecked(AbstractSurefireMojo.java:954)
[ERROR] at org.apache.maven.plugin.surefire.AbstractSurefireMojo.execute(AbstractSurefireMojo.java:832)
[ERROR] at org.apache.maven.plugin.DefaultBuildPluginManager.executeMojo(DefaultBuildPluginManager.java:134)
[ERROR] at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:208)
[ERROR] at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:154)
[ERROR] at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:146)
[ERROR] at org.apache.maven.lifecycle.internal.LifecycleModuleBuilder.buildProject(LifecycleModuleBuilder.java:117)
[ERROR] at org.apache.maven.lifecycle.internal.LifecycleModuleBuilder.buildProject(LifecycleModuleBuilder.java:81)
[ERROR] at org.apache.maven.lifecycle.internal.builder.singlethreaded.SingleThreadedBuilder.build(SingleThreadedBuilder.java:51)
[ERROR] at org.apache.maven.lifecycle.internal.LifecycleStarter.execute(LifecycleStarter.java:128)
[ERROR] at org.apache.maven.DefaultMaven.doExecute(DefaultMaven.java:309)
[ERROR] at org.apache.maven.DefaultMaven.doExecute(DefaultMaven.java:194)
[ERROR] at org.apache.maven.DefaultMaven.execute(DefaultMaven.java:107)
[ERROR] at org.apache.maven.cli.MavenCli.execute(MavenCli.java:955)
[ERROR] at org.apache.maven.cli.MavenCli.doMain(MavenCli.java:290)
[ERROR] at org.apache.maven.cli.MavenCli.main(MavenCli.java:194)
[ERROR] at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
[ERROR] at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
[ERROR] at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
[ERROR] at java.lang.reflect.Method.invoke(Method.java:498)
[ERROR] at org.codehaus.plexus.classworlds.launcher.Launcher.launchEnhanced(Launcher.java:289)
[ERROR] at org.codehaus.plexus.classworlds.launcher.Launcher.launch(Launcher.java:229)
[ERROR] at org.codehaus.plexus.classworlds.launcher.Launcher.mainWithExitCode(Launcher.java:415)
[ERROR] at org.codehaus.plexus.classworlds.launcher.Launcher.main(Launcher.java:356)
[ERROR] Caused by: org.apache.maven.surefire.booter.SurefireBooterForkException: The forked VM terminated without properly saying goodbye. VM crash or System.exit called?
[ERROR] Command was cmd.exe /X /C ""C:\Program Files\Java\jdk1.8.0_152\jre\bin\java" -Xms256m -Xmx1024m -jar C:\Users\ggregory\AppData\Local\Temp\surefire22320217597495112\surefirebooter1486874613063862199.jar C:\Users\ggregory\AppData\Local\Temp\surefire22320217597495112 2018-01-23T11-03-18_847-jvmRun6 surefire6375637980242546356tmp surefire_441335531705722358735tmp"
[ERROR] Process Exit Code: 0
[ERROR] Crashed tests:
[ERROR] org.apache.logging.log4j.core.appender.HttpAppenderTest
[ERROR] at org.apache.maven.plugin.surefire.booterclient.ForkStarter.fork(ForkStarter.java:686)
[ERROR] at org.apache.maven.plugin.surefire.booterclient.ForkStarter.fork(ForkStarter.java:535)
[ERROR] at org.apache.maven.plugin.surefire.booterclient.ForkStarter.access$700(ForkStarter.java:116)
[ERROR] at org.apache.maven.plugin.surefire.booterclient.ForkStarter$2.call(ForkStarter.java:431)
[ERROR] at org.apache.maven.plugin.surefire.booterclient.ForkStarter$2.call(ForkStarter.java:408)
[ERROR] at java.util.concurrent.FutureTask.run(FutureTask.java:266)
[ERROR] at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
[ERROR] at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
[ERROR] at java.lang.Thread.run(Thread.java:748)
[ERROR]
[ERROR] -> [Help 1]
[ERROR]
[ERROR] To see the full stack trace of the errors, re-run Maven with the -e switch.
[ERROR] Re-run Maven using the -X switch to enable full debug logging.
[ERROR]
[ERROR] For more information about the errors and possible solutions, please read the following articles:
[ERROR] [Help 1] http://cwiki.apache.org/confluence/display/MAVEN/MojoExecutionException
[ERROR]
[ERROR] After correcting the problems, you can resume the build with the command
[ERROR] mvn <goals> -rf :log4j-core
*/
public class HttpAppenderTest {
private static final String LOG_MESSAGE = "Hello, world!";
private static Log4jLogEvent createLogEvent() {
return Log4jLogEvent.newBuilder()
.setLoggerName(HttpAppenderTest.class.getName())
.setLoggerFqcn(HttpAppenderTest.class.getName())
.setLevel(Level.INFO)
.setMessage(new SimpleMessage(LOG_MESSAGE))
.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().dynamicHttpsPort()
.keystorePath(TestConstants.KEYSTORE_FILE)
.keystorePassword(String.valueOf(TestConstants.KEYSTORE_PWD()))
.keystoreType(TestConstants.KEYSTORE_TYPE));
@Test
public void testAppend() throws Exception {
wireMockRule.stubFor(post(urlEqualTo("/test/log4j/"))
.willReturn(SUCCESS_RESPONSE));
final Appender appender = HttpAppender.newBuilder()
.setName("Http")
.setLayout(JsonLayout.createDefaultLayout())
.setConfiguration(ctx.getConfiguration())
.setUrl(new URL("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 testAppendHttps() throws Exception {
wireMockRule.stubFor(post(urlEqualTo("/test/log4j/"))
.willReturn(SUCCESS_RESPONSE));
final Appender appender = HttpAppender.newBuilder()
.setName("Http")
.setLayout(JsonLayout.createDefaultLayout())
.setConfiguration(ctx.getConfiguration())
.setUrl(new URL("https://localhost:" + wireMockRule.httpsPort() + "/test/log4j/"))
.setSslConfiguration(SslConfiguration.createSSLConfiguration(null,
KeyStoreConfiguration.createKeyStoreConfiguration(TestConstants.KEYSTORE_FILE, TestConstants.KEYSTORE_PWD(), null, null, TestConstants.KEYSTORE_TYPE, null),
TrustStoreConfiguration.createKeyStoreConfiguration(TestConstants.TRUSTSTORE_FILE, TestConstants.TRUSTSTORE_PWD(), null ,null, TestConstants.TRUSTSTORE_TYPE, null)))
.setVerifyHostname(false)
.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()
.setName("Http")
.setLayout(JsonLayout.createDefaultLayout())
.setConfiguration(ctx.getConfiguration())
.setMethod("PUT")
.setUrl(new URL("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 testAppendCustomHeader() throws Exception {
wireMockRule.stubFor(post(urlEqualTo("/test/log4j/"))
.willReturn(SUCCESS_RESPONSE));
final Appender appender = HttpAppender.newBuilder()
.setName("Http")
.setLayout(JsonLayout.createDefaultLayout())
.setConfiguration(ctx.getConfiguration())
.setUrl(new URL("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 {
wireMockRule.stubFor(post(urlEqualTo("/test/log4j/"))
.willReturn(FAILURE_RESPONSE));
StatusLogger.getLogger().registerListener(new StatusListener() {
@Override
public void log(final StatusData data) {
error = data;
}
@Override
public Level getStatusLevel() {
return Level.ERROR;
}
@Override
public void close() throws IOException { }
});
error = null;
final Appender appender = HttpAppender.newBuilder()
.setName("Http")
.setLayout(JsonLayout.createDefaultLayout())
.setConfiguration(ctx.getConfiguration())
.setUrl(new URL("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 {
wireMockRule.stubFor(post(urlEqualTo("/test/log4j/"))
.willReturn(FAILURE_RESPONSE));
final Appender appender = HttpAppender.newBuilder()
.setName("Http")
.setLayout(JsonLayout.createDefaultLayout())
.setConfiguration(ctx.getConfiguration())
.setIgnoreExceptions(false)
.setUrl(new URL("http://localhost:" + wireMockRule.port() + "/test/log4j/"))
.build();
appender.append(createLogEvent());
}
@Test(expected = AppenderLoggingException.class)
public void testAppendConnectError() throws Exception {
final Appender appender = HttpAppender.newBuilder()
.setName("Http")
.setLayout(JsonLayout.createDefaultLayout())
.setConfiguration(ctx.getConfiguration())
.setIgnoreExceptions(false)
.setUrl(new URL("http://localhost:"+(wireMockRule.port()+1)+"/test/log4j/"))
.build();
appender.append(createLogEvent());
}
}