You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@logging.apache.org by gg...@apache.org on 2018/01/11 02:19:57 UTC
[1/2] logging-log4j2 git commit: [LOG4J2-2179] The MongoDB Appender
should use a keys and values for a Log4j MapMessage. [LOG4J2-2180] Add a
MongoDbProvider builder for and deprecate
org.apache.logging.log4j.mongodb.MongoDbProvider.createNoSqlProvider().
Repository: logging-log4j2
Updated Branches:
refs/heads/master ed600f7e0 -> 26fc9e079
http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/26fc9e07/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/mom/JmsManager.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/mom/JmsManager.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/mom/JmsManager.java
index c4df884..f7794e6 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/mom/JmsManager.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/mom/JmsManager.java
@@ -419,7 +419,7 @@ public class JmsManager extends AbstractManager {
private MapMessage map(final org.apache.logging.log4j.message.MapMessage<?, ?> log4jMapMessage,
final MapMessage jmsMapMessage) {
- // Map without calling rg.apache.logging.log4j.message.MapMessage#getData() which makes a copy of the map.
+ // Map without calling org.apache.logging.log4j.message.MapMessage#getData() which makes a copy of the map.
log4jMapMessage.forEach(new BiConsumer<String, Object>() {
@Override
public void accept(final String key, final Object value) {
http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/26fc9e07/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/nosql/NoSqlAppender.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/nosql/NoSqlAppender.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/nosql/NoSqlAppender.java
index c26ad8f..aae28ff 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/nosql/NoSqlAppender.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/nosql/NoSqlAppender.java
@@ -16,14 +16,17 @@
*/
package org.apache.logging.log4j.core.appender.nosql;
+import java.io.Serializable;
+
import org.apache.logging.log4j.core.Appender;
import org.apache.logging.log4j.core.Filter;
+import org.apache.logging.log4j.core.Layout;
import org.apache.logging.log4j.core.appender.AbstractAppender;
import org.apache.logging.log4j.core.appender.db.AbstractDatabaseAppender;
import org.apache.logging.log4j.core.config.plugins.Plugin;
-import org.apache.logging.log4j.core.config.plugins.PluginAttribute;
+import org.apache.logging.log4j.core.config.plugins.PluginBuilderAttribute;
+import org.apache.logging.log4j.core.config.plugins.PluginBuilderFactory;
import org.apache.logging.log4j.core.config.plugins.PluginElement;
-import org.apache.logging.log4j.core.config.plugins.PluginFactory;
import org.apache.logging.log4j.core.util.Booleans;
/**
@@ -41,39 +44,97 @@ import org.apache.logging.log4j.core.util.Booleans;
*/
@Plugin(name = "NoSql", category = "Core", elementType = Appender.ELEMENT_TYPE, printObject = true)
public final class NoSqlAppender extends AbstractDatabaseAppender<NoSqlDatabaseManager<?>> {
- private final String description;
- private NoSqlAppender(final String name, final Filter filter, final boolean ignoreExceptions,
- final NoSqlDatabaseManager<?> manager) {
- super(name, filter, ignoreExceptions, manager);
- this.description = this.getName() + "{ manager=" + this.getManager() + " }";
- }
+ /**
+ * Builds ConsoleAppender instances.
+ *
+ * @param <B>
+ * The type to build
+ */
+ public static class Builder<B extends Builder<B>> extends AbstractAppender.Builder<B>
+ implements org.apache.logging.log4j.core.util.Builder<NoSqlAppender> {
- @Override
- public String toString() {
- return this.description;
+ @PluginBuilderAttribute("bufferSize")
+ private int bufferSize;
+
+ @PluginElement("NoSqlProvider")
+ private NoSqlProvider<?> provider;
+
+ @SuppressWarnings("resource")
+ @Override
+ public NoSqlAppender build() {
+ final String name = getName();
+ if (provider == null) {
+ LOGGER.error("NoSQL provider not specified for appender [{}].", name);
+ return null;
+ }
+
+ final String managerName = "noSqlManager{ description=" + name + ", bufferSize=" + bufferSize
+ + ", provider=" + provider + " }";
+
+ final NoSqlDatabaseManager<?> manager = NoSqlDatabaseManager.getNoSqlDatabaseManager(managerName,
+ bufferSize, provider);
+ if (manager == null) {
+ return null;
+ }
+
+ return new NoSqlAppender(name, getFilter(), getLayout(), isIgnoreExceptions(), manager);
+ }
+
+ /**
+ * Sets the buffer size.
+ *
+ * @param bufferSize
+ * If an integer greater than 0, this causes the appender to buffer log events and flush whenever the
+ * buffer reaches this size.
+ * @return this
+ */
+ public B setBufferSize(int bufferSize) {
+ this.bufferSize = bufferSize;
+ return asBuilder();
+ }
+
+ /**
+ * Sets the provider.
+ *
+ * @param provider
+ * The NoSQL provider that provides connections to the chosen NoSQL database.
+ * @return this
+ */
+ public B setProvider(NoSqlProvider<?> provider) {
+ this.provider = provider;
+ return asBuilder();
+ }
}
/**
* Factory method for creating a NoSQL appender within the plugin manager.
*
- * @param name The name of the appender.
- * @param ignore If {@code "true"} (default) exceptions encountered when appending events are logged; otherwise
- * they are propagated to the caller.
- * @param filter The filter, if any, to use.
- * @param bufferSize If an integer greater than 0, this causes the appender to buffer log events and flush whenever
- * the buffer reaches this size.
- * @param provider The NoSQL provider that provides connections to the chosen NoSQL database.
+ * @param name
+ * The name of the appender.
+ * @param ignore
+ * If {@code "true"} (default) exceptions encountered when appending events are logged; otherwise they
+ * are propagated to the caller.
+ * @param filter
+ * The filter, if any, to use.
+ * @param bufferSize
+ * If an integer greater than 0, this causes the appender to buffer log events and flush whenever the
+ * buffer reaches this size.
+ * @param provider
+ * The NoSQL provider that provides connections to the chosen NoSQL database.
* @return a new NoSQL appender.
+ * @deprecated since 2.10.1; use {@link Builder}.
*/
@SuppressWarnings("resource")
- @PluginFactory
+ @Deprecated
public static NoSqlAppender createAppender(
- @PluginAttribute("name") final String name,
- @PluginAttribute("ignoreExceptions") final String ignore,
- @PluginElement("Filter") final Filter filter,
- @PluginAttribute("bufferSize") final String bufferSize,
- @PluginElement("NoSqlProvider") final NoSqlProvider<?> provider) {
+ // @formatter:off
+ final String name,
+ final String ignore,
+ final Filter filter,
+ final String bufferSize,
+ final NoSqlProvider<?> provider) {
+ // @formatter:on
if (provider == null) {
LOGGER.error("NoSQL provider not specified for appender [{}].", name);
return null;
@@ -82,16 +143,33 @@ public final class NoSqlAppender extends AbstractDatabaseAppender<NoSqlDatabaseM
final int bufferSizeInt = AbstractAppender.parseInt(bufferSize, 0);
final boolean ignoreExceptions = Booleans.parseBoolean(ignore, true);
- final String managerName = "noSqlManager{ description=" + name + ", bufferSize=" + bufferSizeInt
- + ", provider=" + provider + " }";
+ final String managerName = "noSqlManager{ description=" + name + ", bufferSize=" + bufferSizeInt + ", provider="
+ + provider + " }";
- final NoSqlDatabaseManager<?> manager = NoSqlDatabaseManager.getNoSqlDatabaseManager(
- managerName, bufferSizeInt, provider
- );
+ final NoSqlDatabaseManager<?> manager = NoSqlDatabaseManager.getNoSqlDatabaseManager(managerName, bufferSizeInt,
+ provider);
if (manager == null) {
return null;
}
- return new NoSqlAppender(name, filter, ignoreExceptions, manager);
+ return new NoSqlAppender(name, filter, null, ignoreExceptions, manager);
+ }
+
+ @PluginBuilderFactory
+ public static <B extends Builder<B>> B newBuilder() {
+ return new Builder<B>().asBuilder();
+ }
+
+ private final String description;
+
+ private NoSqlAppender(final String name, final Filter filter, Layout<? extends Serializable> layout,
+ final boolean ignoreExceptions, final NoSqlDatabaseManager<?> manager) {
+ super(name, filter, layout, ignoreExceptions, manager);
+ this.description = this.getName() + "{ manager=" + this.getManager() + " }";
+ }
+
+ @Override
+ public String toString() {
+ return this.description;
}
}
http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/26fc9e07/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/nosql/NoSqlDatabaseManager.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/nosql/NoSqlDatabaseManager.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/nosql/NoSqlDatabaseManager.java
index a0a29ce..361ae2b 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/nosql/NoSqlDatabaseManager.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/nosql/NoSqlDatabaseManager.java
@@ -16,6 +16,10 @@
*/
package org.apache.logging.log4j.core.appender.nosql;
+import java.io.Serializable;
+
+import javax.jms.JMSException;
+
import org.apache.logging.log4j.Marker;
import org.apache.logging.log4j.ThreadContext;
import org.apache.logging.log4j.core.LogEvent;
@@ -23,6 +27,7 @@ import org.apache.logging.log4j.core.appender.AppenderLoggingException;
import org.apache.logging.log4j.core.appender.ManagerFactory;
import org.apache.logging.log4j.core.appender.db.AbstractDatabaseManager;
import org.apache.logging.log4j.core.util.Closer;
+import org.apache.logging.log4j.message.MapMessage;
import org.apache.logging.log4j.util.BiConsumer;
import org.apache.logging.log4j.util.ReadOnlyStringMap;
@@ -64,14 +69,40 @@ public final class NoSqlDatabaseManager<W> extends AbstractDatabaseManager {
}
}
+ @Deprecated
@Override
protected void writeInternal(final LogEvent event) {
+ writeInternal(event, null);
+ }
+
+ @Override
+ protected void writeInternal(final LogEvent event, final Serializable serializable) {
if (!this.isRunning() || this.connection == null || this.connection.isClosed()) {
throw new AppenderLoggingException(
"Cannot write logging event; NoSQL manager not connected to the database.");
}
final NoSqlObject<W> entity = this.connection.createObject();
+ if (serializable instanceof MapMessage) {
+ setFields((MapMessage<?, ?>) serializable, entity);
+ } else {
+ setFields(event, entity);
+ }
+
+ this.connection.insertObject(entity);
+ }
+
+ private void setFields(final MapMessage<?, ?> mapMessage, final NoSqlObject<W> noSqlObject) {
+ // Map without calling org.apache.logging.log4j.message.MapMessage#getData() which makes a copy of the map.
+ mapMessage.forEach(new BiConsumer<String, Object>() {
+ @Override
+ public void accept(final String key, final Object value) {
+ noSqlObject.set(key, value);
+ }
+ });
+ }
+
+ private void setFields(final LogEvent event, final NoSqlObject<W> entity) {
entity.set("level", event.getLevel());
entity.set("loggerName", event.getLoggerName());
entity.set("message", event.getMessage() == null ? null : event.getMessage().getFormattedMessage());
@@ -139,8 +170,6 @@ public final class NoSqlDatabaseManager<W> extends AbstractDatabaseManager {
} else {
entity.set("contextStack", contextStack.asList().toArray());
}
-
- this.connection.insertObject(entity);
}
private NoSqlObject<W> buildMarkerEntity(final Marker marker) {
http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/26fc9e07/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/db/AbstractDatabaseAppenderTest.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/db/AbstractDatabaseAppenderTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/db/AbstractDatabaseAppenderTest.java
index cf33cea..c21311a 100644
--- a/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/db/AbstractDatabaseAppenderTest.java
+++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/db/AbstractDatabaseAppenderTest.java
@@ -95,14 +95,14 @@ public class AbstractDatabaseAppenderTest {
appender.append(event1);
then(manager).should().connectAndStart();
- then(manager).should().writeInternal(same(event1));
+ then(manager).should().writeInternal(same(event1), null);
then(manager).should().commitAndClose();
reset(manager);
appender.append(event2);
then(manager).should().connectAndStart();
- then(manager).should().writeInternal(same(event2));
+ then(manager).should().writeInternal(same(event2), null);
then(manager).should().commitAndClose();
}
http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/26fc9e07/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/db/AbstractDatabaseManagerTest.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/db/AbstractDatabaseManagerTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/db/AbstractDatabaseManagerTest.java
index 41e7dd8..26462c3 100644
--- a/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/db/AbstractDatabaseManagerTest.java
+++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/db/AbstractDatabaseManagerTest.java
@@ -24,6 +24,8 @@ import static org.mockito.ArgumentMatchers.same;
import static org.mockito.BDDMockito.then;
import static org.mockito.Mockito.*;
+import java.io.Serializable;
+
public class AbstractDatabaseManagerTest {
private AbstractDatabaseManager manager;
@@ -89,21 +91,21 @@ public class AbstractDatabaseManagerTest {
then(manager).should().startupInternal();
reset(manager);
- manager.write(event1);
+ manager.write(event1, null);
then(manager).should().connectAndStart();
- then(manager).should().writeInternal(same(event1));
+ then(manager).should().writeInternal(same(event1), null);
then(manager).should().commitAndClose();
reset(manager);
- manager.write(event2);
+ manager.write(event2, null);
then(manager).should().connectAndStart();
- then(manager).should().writeInternal(same(event2));
+ then(manager).should().writeInternal(same(event2), null);
then(manager).should().commitAndClose();
reset(manager);
- manager.write(event3);
+ manager.write(event3, null);
then(manager).should().connectAndStart();
- then(manager).should().writeInternal(same(event3));
+ then(manager).should().writeInternal(same(event3), null);
then(manager).should().commitAndClose();
then(manager).shouldHaveNoMoreInteractions();
}
@@ -130,16 +132,16 @@ public class AbstractDatabaseManagerTest {
manager.startup();
then(manager).should().startupInternal();
- manager.write(event1);
- manager.write(event2);
- manager.write(event3);
- manager.write(event4);
+ manager.write(event1, null);
+ manager.write(event2, null);
+ manager.write(event3, null);
+ manager.write(event4, null);
then(manager).should().connectAndStart();
- then(manager).should().writeInternal(same(event1copy));
- then(manager).should().writeInternal(same(event2copy));
- then(manager).should().writeInternal(same(event3copy));
- then(manager).should().writeInternal(same(event4copy));
+ then(manager).should().writeInternal(same(event1copy), null);
+ then(manager).should().writeInternal(same(event2copy), null);
+ then(manager).should().writeInternal(same(event3copy), null);
+ then(manager).should().writeInternal(same(event4copy), null);
then(manager).should().commitAndClose();
then(manager).shouldHaveNoMoreInteractions();
}
@@ -163,15 +165,15 @@ public class AbstractDatabaseManagerTest {
manager.startup();
then(manager).should().startupInternal();
- manager.write(event1);
- manager.write(event2);
- manager.write(event3);
+ manager.write(event1, null);
+ manager.write(event2, null);
+ manager.write(event3, null);
manager.flush();
then(manager).should().connectAndStart();
- then(manager).should().writeInternal(same(event1copy));
- then(manager).should().writeInternal(same(event2copy));
- then(manager).should().writeInternal(same(event3copy));
+ then(manager).should().writeInternal(same(event1copy), null);
+ then(manager).should().writeInternal(same(event2copy), null);
+ then(manager).should().writeInternal(same(event3copy), null);
then(manager).should().commitAndClose();
then(manager).shouldHaveNoMoreInteractions();
}
@@ -195,15 +197,15 @@ public class AbstractDatabaseManagerTest {
manager.startup();
then(manager).should().startupInternal();
- manager.write(event1);
- manager.write(event2);
- manager.write(event3);
+ manager.write(event1, null);
+ manager.write(event2, null);
+ manager.write(event3, null);
manager.shutdown();
then(manager).should().connectAndStart();
- then(manager).should().writeInternal(same(event1copy));
- then(manager).should().writeInternal(same(event2copy));
- then(manager).should().writeInternal(same(event3copy));
+ then(manager).should().writeInternal(same(event1copy), null);
+ then(manager).should().writeInternal(same(event2copy), null);
+ then(manager).should().writeInternal(same(event3copy), null);
then(manager).should().commitAndClose();
then(manager).should().shutdownInternal();
then(manager).shouldHaveNoMoreInteractions();
@@ -218,6 +220,7 @@ public class AbstractDatabaseManagerTest {
@Override
protected void startupInternal() throws Exception {
+ // noop
}
@Override
@@ -227,15 +230,23 @@ public class AbstractDatabaseManagerTest {
@Override
protected void connectAndStart() {
+ // noop
}
+ @Deprecated
@Override
protected void writeInternal(final LogEvent event) {
+ // noop
}
@Override
+ protected void writeInternal(LogEvent event, Serializable serializable) {
+ // noop
+ }
+ @Override
protected boolean commitAndClose() {
return true;
}
+
}
}
http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/26fc9e07/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/nosql/NoSqlDatabaseManagerTest.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/nosql/NoSqlDatabaseManagerTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/nosql/NoSqlDatabaseManagerTest.java
index 7597cb5..772a947 100644
--- a/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/nosql/NoSqlDatabaseManagerTest.java
+++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/nosql/NoSqlDatabaseManagerTest.java
@@ -102,7 +102,7 @@ public class NoSqlDatabaseManagerTest {
try (final NoSqlDatabaseManager<?> manager = NoSqlDatabaseManager.getNoSqlDatabaseManager("name", 0,
provider)) {
expectedException.expect(AppenderLoggingException.class);
- manager.writeInternal(mock(LogEvent.class));
+ manager.writeInternal(mock(LogEvent.class), null);
}
}
@@ -118,7 +118,7 @@ public class NoSqlDatabaseManagerTest {
then(provider).should().getConnection();
expectedException.expect(AppenderLoggingException.class);
- manager.writeInternal(mock(LogEvent.class));
+ manager.writeInternal(mock(LogEvent.class), null);
}
}
@@ -145,7 +145,7 @@ public class NoSqlDatabaseManagerTest {
.setTimeMillis(1234567890123L)
.build();
- manager.writeInternal(event);
+ manager.writeInternal(event, null);
then(connection).should().insertObject(captor.capture());
final NoSqlObject<Map<String, Object>> inserted = captor.getValue();
@@ -217,7 +217,7 @@ public class NoSqlDatabaseManagerTest {
.setContextStack(stack)
.build();
- manager.writeInternal(event);
+ manager.writeInternal(event, null);
then(connection).should().insertObject(captor.capture());
final NoSqlObject<Map<String, Object>> inserted = captor.getValue();
@@ -318,7 +318,7 @@ public class NoSqlDatabaseManagerTest {
.setContextStack(stack)
.build();
- manager.writeInternal(event);
+ manager.writeInternal(event, null);
then(connection).should().insertObject(captor.capture());
final NoSqlObject<Map<String, Object>> inserted = captor.getValue();
http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/26fc9e07/log4j-core/src/test/java/org/apache/logging/log4j/test/AvailablePortSystemPropertyRule.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/test/AvailablePortSystemPropertyRule.java b/log4j-core/src/test/java/org/apache/logging/log4j/test/AvailablePortSystemPropertyRule.java
deleted file mode 100644
index 0098057..0000000
--- a/log4j-core/src/test/java/org/apache/logging/log4j/test/AvailablePortSystemPropertyRule.java
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * 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.test;
-
-import org.junit.rules.TestRule;
-import org.junit.runner.Description;
-import org.junit.runners.model.Statement;
-
-/**
- * A JUnit TestRule to discover an available port and save it in a system property. Useful for setting up tests using
- * Apache Active MQ.
- */
-public class AvailablePortSystemPropertyRule implements TestRule {
-
- public static AvailablePortSystemPropertyRule create(final String name) {
- return new AvailablePortSystemPropertyRule(name);
- }
-
- protected final String name;
- protected int port;
-
- protected AvailablePortSystemPropertyRule(final String name) {
- this.name = name;
- }
-
- @Override
- public Statement apply(final Statement base, final Description description) {
- return new Statement() {
-
- @Override
- public void evaluate() throws Throwable {
- final String oldValue = System.getProperty(name);
- try {
- port = AvailablePortFinder.getNextAvailable();
- System.setProperty(name, Integer.toString(port));
- base.evaluate();
- } finally {
- // Restore if previously set
- if (oldValue != null) {
- System.setProperty(name, oldValue);
- }
- }
- }
- };
- }
-
- public String getName() {
- return name;
- }
-
- public int getPort() {
- return port;
- }
-
- @Override
- public String toString() {
- final StringBuilder builder = new StringBuilder();
- builder.append("AvailablePortSystemPropertyRule [name=");
- builder.append(name);
- builder.append(", port=");
- builder.append(port);
- builder.append("]");
- return builder.toString();
- }
-
-}
http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/26fc9e07/log4j-core/src/test/java/org/apache/logging/log4j/test/AvailablePortSystemPropertyTestRule.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/test/AvailablePortSystemPropertyTestRule.java b/log4j-core/src/test/java/org/apache/logging/log4j/test/AvailablePortSystemPropertyTestRule.java
new file mode 100644
index 0000000..1bece7b
--- /dev/null
+++ b/log4j-core/src/test/java/org/apache/logging/log4j/test/AvailablePortSystemPropertyTestRule.java
@@ -0,0 +1,81 @@
+/*
+ * 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.test;
+
+import org.junit.rules.TestRule;
+import org.junit.runner.Description;
+import org.junit.runners.model.Statement;
+
+/**
+ * A JUnit TestRule to discover an available port and save it in a system property. Useful for setting up tests using
+ * Apache Active MQ.
+ */
+public class AvailablePortSystemPropertyTestRule implements TestRule {
+
+ public static AvailablePortSystemPropertyTestRule create(final String name) {
+ return new AvailablePortSystemPropertyTestRule(name);
+ }
+
+ protected final String name;
+ protected int port;
+
+ protected AvailablePortSystemPropertyTestRule(final String name) {
+ this.name = name;
+ }
+
+ @Override
+ public Statement apply(final Statement base, final Description description) {
+ return new Statement() {
+
+ @Override
+ public void evaluate() throws Throwable {
+ final String oldValue = System.getProperty(name);
+ try {
+ port = AvailablePortFinder.getNextAvailable();
+ System.setProperty(name, Integer.toString(port));
+ base.evaluate();
+ } finally {
+ // Restore if previously set
+ if (oldValue != null) {
+ System.setProperty(name, oldValue);
+ }
+ }
+ }
+ };
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public int getPort() {
+ return port;
+ }
+
+ @Override
+ public String toString() {
+ final StringBuilder builder = new StringBuilder();
+ builder.append("AvailablePortSystemPropertyRule [name=");
+ builder.append(name);
+ builder.append(", port=");
+ builder.append(port);
+ builder.append("]");
+ return builder.toString();
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/26fc9e07/log4j-mongodb/pom.xml
----------------------------------------------------------------------
diff --git a/log4j-mongodb/pom.xml b/log4j-mongodb/pom.xml
index 8e484ee..2440cfc 100644
--- a/log4j-mongodb/pom.xml
+++ b/log4j-mongodb/pom.xml
@@ -70,6 +70,12 @@
<artifactId>log4j-slf4j-impl</artifactId>
<scope>test</scope>
</dependency>
+ <dependency>
+ <groupId>de.flapdoodle.embed</groupId>
+ <artifactId>de.flapdoodle.embed.mongo</artifactId>
+ <version>2.0.0</version>
+ <scope>test</scope>
+ </dependency>
</dependencies>
<build>
http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/26fc9e07/log4j-mongodb/src/test/java/org/apache/logging/log4j/mongodb/Java8Test.java
----------------------------------------------------------------------
diff --git a/log4j-mongodb/src/test/java/org/apache/logging/log4j/mongodb/Java8Test.java b/log4j-mongodb/src/test/java/org/apache/logging/log4j/mongodb/Java8Test.java
new file mode 100644
index 0000000..817141d
--- /dev/null
+++ b/log4j-mongodb/src/test/java/org/apache/logging/log4j/mongodb/Java8Test.java
@@ -0,0 +1,48 @@
+/*
+ * 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.mongodb;
+
+import org.apache.commons.lang3.JavaVersion;
+import org.apache.commons.lang3.SystemUtils;
+import org.junit.Assume;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Suite;
+
+/**
+ * Runs all MongoDB only on Java 8.
+ * <p>
+ * The test framework {@code de.flapdoodle.embed.mongo} requires Java 8.
+ * </p>
+ */
+@RunWith(Suite.class)
+@Suite.SuiteClasses({ MongoDbTestTestRuleTestJava8.class, MongoDbAuthTestJava8.class, MongoDbCappedTestJava8.class,
+ MongoDbMapMessageTestJava8.class, MongoDbTestJava8.class })
+public class Java8Test {
+
+ @BeforeClass
+ public static void beforeClass() {
+ Assume.assumeTrue(SystemUtils.JAVA_VERSION, SystemUtils.isJavaVersionAtLeast(JavaVersion.JAVA_1_8));
+ }
+
+ @Test
+ public void test() {
+ // noop
+ }
+}
http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/26fc9e07/log4j-mongodb/src/test/java/org/apache/logging/log4j/mongodb/MongoDbAuthTest.java
----------------------------------------------------------------------
diff --git a/log4j-mongodb/src/test/java/org/apache/logging/log4j/mongodb/MongoDbAuthTest.java b/log4j-mongodb/src/test/java/org/apache/logging/log4j/mongodb/MongoDbAuthTest.java
deleted file mode 100644
index 142a470..0000000
--- a/log4j-mongodb/src/test/java/org/apache/logging/log4j/mongodb/MongoDbAuthTest.java
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * 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.mongodb;
-
-import org.apache.logging.log4j.LogManager;
-import org.apache.logging.log4j.Logger;
-import org.apache.logging.log4j.categories.Appenders;
-import org.apache.logging.log4j.junit.LoggerContextRule;
-import org.junit.ClassRule;
-import org.junit.Ignore;
-import org.junit.Test;
-import org.junit.experimental.categories.Category;
-
-@Ignore("Requires a running MongoDB server")
-@Category(Appenders.MongoDb.class)
-public class MongoDbAuthTest {
-
- @ClassRule
- public static LoggerContextRule context = new LoggerContextRule("log4j2-mongodb-auth.xml");
-
- @Test
- public void test() {
- final Logger logger = LogManager.getLogger();
- logger.info("Hello log");
- }
-}
http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/26fc9e07/log4j-mongodb/src/test/java/org/apache/logging/log4j/mongodb/MongoDbAuthTestJava8.java
----------------------------------------------------------------------
diff --git a/log4j-mongodb/src/test/java/org/apache/logging/log4j/mongodb/MongoDbAuthTestJava8.java b/log4j-mongodb/src/test/java/org/apache/logging/log4j/mongodb/MongoDbAuthTestJava8.java
new file mode 100644
index 0000000..64f51a2
--- /dev/null
+++ b/log4j-mongodb/src/test/java/org/apache/logging/log4j/mongodb/MongoDbAuthTestJava8.java
@@ -0,0 +1,52 @@
+/*
+ * 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.mongodb;
+
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+import org.apache.logging.log4j.categories.Appenders;
+import org.apache.logging.log4j.junit.LoggerContextRule;
+import org.apache.logging.log4j.test.AvailablePortSystemPropertyTestRule;
+import org.apache.logging.log4j.test.RuleChainFactory;
+import org.junit.ClassRule;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+import org.junit.rules.RuleChain;
+
+/**
+ * This class name does NOT end in "Test" in order to only be picked up by {@link Java8Test}.
+ */
+@Category(Appenders.MongoDb.class)
+public class MongoDbAuthTestJava8 {
+
+ static LoggerContextRule loggerContextTestRule = new LoggerContextRule("log4j2-mongodb-auth.xml");
+
+ static final AvailablePortSystemPropertyTestRule mongoDbPortTestRule = AvailablePortSystemPropertyTestRule
+ .create(MongoDbTestJava8.class.getName());
+
+ static final MongoDbTestRule mongoDbTestRule = new MongoDbTestRule(mongoDbPortTestRule.getName());
+
+ @ClassRule
+ public static RuleChain ruleChain = RuleChainFactory.create(mongoDbPortTestRule, mongoDbTestRule,
+ loggerContextTestRule);
+
+ @Test
+ public void test() {
+ final Logger logger = LogManager.getLogger();
+ logger.info("Hello log");
+ }
+}
http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/26fc9e07/log4j-mongodb/src/test/java/org/apache/logging/log4j/mongodb/MongoDbCappedTest.java
----------------------------------------------------------------------
diff --git a/log4j-mongodb/src/test/java/org/apache/logging/log4j/mongodb/MongoDbCappedTest.java b/log4j-mongodb/src/test/java/org/apache/logging/log4j/mongodb/MongoDbCappedTest.java
deleted file mode 100644
index d5aa5a9..0000000
--- a/log4j-mongodb/src/test/java/org/apache/logging/log4j/mongodb/MongoDbCappedTest.java
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * 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.mongodb;
-
-import org.apache.logging.log4j.LogManager;
-import org.apache.logging.log4j.Logger;
-import org.apache.logging.log4j.categories.Appenders;
-import org.apache.logging.log4j.junit.LoggerContextRule;
-import org.junit.ClassRule;
-import org.junit.Ignore;
-import org.junit.Test;
-import org.junit.experimental.categories.Category;
-
-@Ignore("Requires a running MongoDB server")
-@Category(Appenders.MongoDb.class)
-public class MongoDbCappedTest {
-
- @ClassRule
- public static LoggerContextRule context = new LoggerContextRule("log4j2-mongodb-capped.xml");
-
- @Test
- public void test() {
- final Logger logger = LogManager.getLogger();
- logger.info("Hello log");
- }
-}
http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/26fc9e07/log4j-mongodb/src/test/java/org/apache/logging/log4j/mongodb/MongoDbCappedTestJava8.java
----------------------------------------------------------------------
diff --git a/log4j-mongodb/src/test/java/org/apache/logging/log4j/mongodb/MongoDbCappedTestJava8.java b/log4j-mongodb/src/test/java/org/apache/logging/log4j/mongodb/MongoDbCappedTestJava8.java
new file mode 100644
index 0000000..78668f3
--- /dev/null
+++ b/log4j-mongodb/src/test/java/org/apache/logging/log4j/mongodb/MongoDbCappedTestJava8.java
@@ -0,0 +1,52 @@
+/*
+ * 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.mongodb;
+
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+import org.apache.logging.log4j.categories.Appenders;
+import org.apache.logging.log4j.junit.LoggerContextRule;
+import org.apache.logging.log4j.test.AvailablePortSystemPropertyTestRule;
+import org.apache.logging.log4j.test.RuleChainFactory;
+import org.junit.ClassRule;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+import org.junit.rules.RuleChain;
+
+/**
+ * This class name does NOT end in "Test" in order to only be picked up by {@link Java8Test}.
+ */
+@Category(Appenders.MongoDb.class)
+public class MongoDbCappedTestJava8 {
+
+ static LoggerContextRule loggerContextTestRule = new LoggerContextRule("log4j2-mongodb-capped.xml");
+
+ static final AvailablePortSystemPropertyTestRule mongoDbPortTestRule = AvailablePortSystemPropertyTestRule
+ .create(MongoDbTestJava8.class.getName());
+
+ static final MongoDbTestRule mongoDbTestRule = new MongoDbTestRule(mongoDbPortTestRule.getName());
+
+ @ClassRule
+ public static RuleChain ruleChain = RuleChainFactory.create(mongoDbPortTestRule, mongoDbTestRule,
+ loggerContextTestRule);
+
+ @Test
+ public void test() {
+ final Logger logger = LogManager.getLogger();
+ logger.info("Hello log");
+ }
+}
http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/26fc9e07/log4j-mongodb/src/test/java/org/apache/logging/log4j/mongodb/MongoDbMapMessageTestJava8.java
----------------------------------------------------------------------
diff --git a/log4j-mongodb/src/test/java/org/apache/logging/log4j/mongodb/MongoDbMapMessageTestJava8.java b/log4j-mongodb/src/test/java/org/apache/logging/log4j/mongodb/MongoDbMapMessageTestJava8.java
new file mode 100644
index 0000000..76432ee
--- /dev/null
+++ b/log4j-mongodb/src/test/java/org/apache/logging/log4j/mongodb/MongoDbMapMessageTestJava8.java
@@ -0,0 +1,74 @@
+/*
+ * 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.mongodb;
+
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+import org.apache.logging.log4j.categories.Appenders;
+import org.apache.logging.log4j.junit.LoggerContextRule;
+import org.apache.logging.log4j.message.MapMessage;
+import org.apache.logging.log4j.test.AvailablePortSystemPropertyTestRule;
+import org.apache.logging.log4j.test.RuleChainFactory;
+import org.bson.Document;
+import org.junit.Assert;
+import org.junit.ClassRule;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+import org.junit.rules.RuleChain;
+
+import com.mongodb.MongoClient;
+import com.mongodb.client.MongoCollection;
+import com.mongodb.client.MongoDatabase;
+
+/**
+ * This class name does NOT end in "Test" in order to only be picked up by {@link Java8Test}.
+ */
+@Category(Appenders.MongoDb.class)
+public class MongoDbMapMessageTestJava8 {
+
+ static LoggerContextRule loggerContextTestRule = new LoggerContextRule("log4j2-mongodb-map-message.xml");
+
+ static final AvailablePortSystemPropertyTestRule mongoDbPortTestRule = AvailablePortSystemPropertyTestRule
+ .create(MongoDbMapMessageTestJava8.class.getName());
+
+ static final MongoDbTestRule mongoDbTestRule = new MongoDbTestRule(mongoDbPortTestRule.getName());
+
+ @ClassRule
+ public static RuleChain ruleChain = RuleChainFactory.create(mongoDbPortTestRule, mongoDbTestRule,
+ loggerContextTestRule);
+
+ @Test
+ public void test() {
+ final Logger logger = LogManager.getLogger();
+ final MapMessage<?, Object> map = new MapMessage<>();
+ map.with("SomeName", "SomeValue");
+ map.with("SomeInt", 1);
+ logger.info(map);
+ //
+ try (final MongoClient mongoClient = mongoDbTestRule.getMongoClient()) {
+ final MongoDatabase database = mongoClient.getDatabase("test");
+ Assert.assertNotNull(database);
+ final MongoCollection<Document> collection = database.getCollection("applog");
+ Assert.assertNotNull(collection);
+ Document first = collection.find().first();
+ Assert.assertNotNull(first);
+ Assert.assertEquals(first.toJson(), "SomeValue", first.getString("SomeName"));
+ Assert.assertEquals(first.toJson(), Integer.valueOf(1), first.getInteger("SomeInt"));
+ }
+
+ }
+}
http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/26fc9e07/log4j-mongodb/src/test/java/org/apache/logging/log4j/mongodb/MongoDbTest.java
----------------------------------------------------------------------
diff --git a/log4j-mongodb/src/test/java/org/apache/logging/log4j/mongodb/MongoDbTest.java b/log4j-mongodb/src/test/java/org/apache/logging/log4j/mongodb/MongoDbTest.java
deleted file mode 100644
index eab3c1c..0000000
--- a/log4j-mongodb/src/test/java/org/apache/logging/log4j/mongodb/MongoDbTest.java
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * 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.mongodb;
-
-import org.apache.logging.log4j.LogManager;
-import org.apache.logging.log4j.Logger;
-import org.apache.logging.log4j.categories.Appenders;
-import org.apache.logging.log4j.junit.LoggerContextRule;
-import org.junit.ClassRule;
-import org.junit.Ignore;
-import org.junit.Test;
-import org.junit.experimental.categories.Category;
-
-@Ignore("Requires a running MongoDB server")
-@Category(Appenders.MongoDb.class)
-public class MongoDbTest {
-
- @ClassRule
- public static LoggerContextRule context = new LoggerContextRule("log4j2-mongodb.xml");
-
- @Test
- public void test() {
- final Logger logger = LogManager.getLogger();
- logger.info("Hello log");
- }
-}
http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/26fc9e07/log4j-mongodb/src/test/java/org/apache/logging/log4j/mongodb/MongoDbTestJava8.java
----------------------------------------------------------------------
diff --git a/log4j-mongodb/src/test/java/org/apache/logging/log4j/mongodb/MongoDbTestJava8.java b/log4j-mongodb/src/test/java/org/apache/logging/log4j/mongodb/MongoDbTestJava8.java
new file mode 100644
index 0000000..032eb73
--- /dev/null
+++ b/log4j-mongodb/src/test/java/org/apache/logging/log4j/mongodb/MongoDbTestJava8.java
@@ -0,0 +1,52 @@
+/*
+ * 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.mongodb;
+
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+import org.apache.logging.log4j.categories.Appenders;
+import org.apache.logging.log4j.junit.LoggerContextRule;
+import org.apache.logging.log4j.test.AvailablePortSystemPropertyTestRule;
+import org.apache.logging.log4j.test.RuleChainFactory;
+import org.junit.ClassRule;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+import org.junit.rules.RuleChain;
+
+/**
+ * This class name does NOT end in "Test" in order to only be picked up by {@link Java8Test}.
+ */
+@Category(Appenders.MongoDb.class)
+public class MongoDbTestJava8 {
+
+ static LoggerContextRule loggerContextTestRule = new LoggerContextRule("log4j2-mongodb.xml");
+
+ static final AvailablePortSystemPropertyTestRule mongoDbPortTestRule = AvailablePortSystemPropertyTestRule
+ .create(MongoDbTestJava8.class.getName());
+
+ static final MongoDbTestRule mongoDbTestRule = new MongoDbTestRule(mongoDbPortTestRule.getName());
+
+ @ClassRule
+ public static RuleChain ruleChain = RuleChainFactory.create(mongoDbPortTestRule, mongoDbTestRule,
+ loggerContextTestRule);
+
+ @Test
+ public void test() {
+ final Logger logger = LogManager.getLogger();
+ logger.info("Hello log");
+ }
+}
http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/26fc9e07/log4j-mongodb/src/test/java/org/apache/logging/log4j/mongodb/MongoDbTestRule.java
----------------------------------------------------------------------
diff --git a/log4j-mongodb/src/test/java/org/apache/logging/log4j/mongodb/MongoDbTestRule.java b/log4j-mongodb/src/test/java/org/apache/logging/log4j/mongodb/MongoDbTestRule.java
new file mode 100644
index 0000000..73fef40
--- /dev/null
+++ b/log4j-mongodb/src/test/java/org/apache/logging/log4j/mongodb/MongoDbTestRule.java
@@ -0,0 +1,139 @@
+/*
+ * 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.mongodb;
+
+import java.util.Objects;
+
+import org.junit.rules.TestRule;
+import org.junit.runner.Description;
+import org.junit.runners.model.Statement;
+
+import com.mongodb.MongoClient;
+
+import de.flapdoodle.embed.mongo.MongodExecutable;
+import de.flapdoodle.embed.mongo.MongodProcess;
+import de.flapdoodle.embed.mongo.MongodStarter;
+import de.flapdoodle.embed.mongo.config.MongodConfigBuilder;
+import de.flapdoodle.embed.mongo.config.Net;
+import de.flapdoodle.embed.mongo.config.Timeout;
+import de.flapdoodle.embed.mongo.distribution.Version;
+import de.flapdoodle.embed.process.runtime.Network;
+
+/**
+ * A JUnit test rule to manage a MongoDB embedded instance.
+ */
+public class MongoDbTestRule implements TestRule {
+
+ private static final int BUILDER_TIMEOUT_MILLIS = 30000;
+
+ /**
+ * Store {@link MongodStarter} (or RuntimeConfig) in a static final field if you want to use artifact store caching
+ * (or else disable caching).
+ * <p>
+ * The test framework {@code de.flapdoodle.embed.mongo} requires Java 8.
+ * </p>
+ */
+ protected static final MongodStarter starter = MongodStarter.getDefaultInstance();
+
+ public static int getBuilderTimeoutMillis() {
+ return BUILDER_TIMEOUT_MILLIS;
+ }
+
+ public static MongodStarter getStarter() {
+ return starter;
+ }
+
+ protected final String portSystemPropertyName;
+ protected MongoClient mongoClient;
+ protected MongodExecutable mongodExecutable;
+ protected MongodProcess mongodProcess;
+
+ /**
+ * Constructs a new test rule.
+ *
+ * @param portSystemPropertyName
+ * The system property name for the MongoDB port.
+ */
+ public MongoDbTestRule(final String portSystemPropertyName) {
+ this.portSystemPropertyName = Objects.requireNonNull(portSystemPropertyName, "portSystemPropertyName");
+ }
+
+ @Override
+ public Statement apply(final Statement base, final Description description) {
+ return new Statement() {
+
+ @Override
+ public void evaluate() throws Throwable {
+ final String value = Objects.requireNonNull(System.getProperty(portSystemPropertyName),
+ "System property '" + portSystemPropertyName + "' is null");
+ final int port = Integer.parseInt(value);
+ mongodExecutable = starter.prepare(
+ // @formatter:off
+ new MongodConfigBuilder()
+ .version(Version.Main.PRODUCTION)
+ .timeout(new Timeout(BUILDER_TIMEOUT_MILLIS))
+ .net(
+ new Net("localhost", port, Network.localhostIsIPv6()))
+ .build());
+ // @formatter:on
+ mongodProcess = mongodExecutable.start();
+ mongoClient = new MongoClient("localhost", port);
+ try {
+ base.evaluate();
+ } finally {
+ if (mongodProcess != null) {
+ mongodProcess.stop();
+ mongodProcess = null;
+ }
+ if (mongodExecutable != null) {
+ mongodExecutable.stop();
+ mongodExecutable = null;
+ }
+ }
+ }
+ };
+ }
+
+ public MongoClient getMongoClient() {
+ return mongoClient;
+ }
+
+ public MongodExecutable getMongodExecutable() {
+ return mongodExecutable;
+ }
+
+ public MongodProcess getMongodProcess() {
+ return mongodProcess;
+ }
+
+ @Override
+ public String toString() {
+ final StringBuilder builder = new StringBuilder();
+ builder.append("MongoDbTestRule [portSystemPropertyName=");
+ builder.append(portSystemPropertyName);
+ builder.append(", mongoClient=");
+ builder.append(mongoClient);
+ builder.append(", mongodExecutable=");
+ builder.append(mongodExecutable);
+ builder.append(", mongodProcess=");
+ builder.append(mongodProcess);
+ builder.append("]");
+ return builder.toString();
+ }
+
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/26fc9e07/log4j-mongodb/src/test/java/org/apache/logging/log4j/mongodb/MongoDbTestTestRuleTestJava8.java
----------------------------------------------------------------------
diff --git a/log4j-mongodb/src/test/java/org/apache/logging/log4j/mongodb/MongoDbTestTestRuleTestJava8.java b/log4j-mongodb/src/test/java/org/apache/logging/log4j/mongodb/MongoDbTestTestRuleTestJava8.java
new file mode 100644
index 0000000..545c959
--- /dev/null
+++ b/log4j-mongodb/src/test/java/org/apache/logging/log4j/mongodb/MongoDbTestTestRuleTestJava8.java
@@ -0,0 +1,69 @@
+/*
+ * 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.mongodb;
+
+import org.apache.commons.lang3.JavaVersion;
+import org.apache.commons.lang3.SystemUtils;
+import org.apache.logging.log4j.test.AvailablePortSystemPropertyTestRule;
+import org.apache.logging.log4j.test.RuleChainFactory;
+import org.junit.Assert;
+import org.junit.Assume;
+import org.junit.BeforeClass;
+import org.junit.ClassRule;
+import org.junit.Test;
+import org.junit.rules.RuleChain;
+
+import com.mongodb.client.MongoIterable;
+
+/**
+ * Tests MongoDbRule. This class name does NOT end in "Test" in order to only be picked up by {@link Java8Test}.
+ * <p>
+ * The test framework {@code de.flapdoodle.embed.mongo} requires Java 8.
+ * </p>
+ */
+public class MongoDbTestTestRuleTestJava8 {
+
+ @BeforeClass
+ public static void beforeClass() {
+ Assume.assumeTrue(SystemUtils.isJavaVersionAtLeast(JavaVersion.JAVA_1_8));
+ }
+
+ public static final AvailablePortSystemPropertyTestRule mongoDbPortTestRule = AvailablePortSystemPropertyTestRule
+ .create(MongoDbTestTestRuleTestJava8.class.getName());
+
+ public static final MongoDbTestRule mongoDbTestRule = new MongoDbTestRule(mongoDbPortTestRule.getName());
+
+ @ClassRule
+ public static RuleChain mongoDbChain = RuleChainFactory.create(mongoDbPortTestRule, mongoDbTestRule);
+
+ @Test
+ public void testAccess() {
+ final MongoIterable<String> databaseNames = mongoDbTestRule.getMongoClient().listDatabaseNames();
+ Assert.assertNotNull(databaseNames);
+ Assert.assertNotNull(databaseNames.first());
+ }
+
+ @Test
+ public void testMongoDbTestRule() {
+ Assert.assertNotNull(MongoDbTestRule.getStarter());
+ Assert.assertNotNull(mongoDbTestRule);
+ Assert.assertNotNull(mongoDbTestRule.getMongoClient());
+ Assert.assertNotNull(mongoDbTestRule.getMongodExecutable());
+ Assert.assertNotNull(mongoDbTestRule.getMongodProcess());
+ }
+}
http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/26fc9e07/log4j-mongodb/src/test/resources/log4j2-mongodb-map-message.xml
----------------------------------------------------------------------
diff --git a/log4j-mongodb/src/test/resources/log4j2-mongodb-map-message.xml b/log4j-mongodb/src/test/resources/log4j2-mongodb-map-message.xml
new file mode 100644
index 0000000..84e49e5
--- /dev/null
+++ b/log4j-mongodb/src/test/resources/log4j2-mongodb-map-message.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 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. -->
+<Configuration status="debug">
+ <Appenders>
+ <NoSql name="MongoDbAppender">
+ <MongoDb databaseName="test" collectionName="applog" server="localhost"
+ port="${sys:org.apache.logging.log4j.mongodb.MongoDbMapMessageTestJava8:-27017}">
+ </MongoDb>
+ <MessageLayout />
+ </NoSql>
+ </Appenders>
+ <Loggers>
+ <Root level="ALL">
+ <AppenderRef ref="MongoDbAppender" />
+ </Root>
+ </Loggers>
+</Configuration>
http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/26fc9e07/src/changes/changes.xml
----------------------------------------------------------------------
diff --git a/src/changes/changes.xml b/src/changes/changes.xml
index 52ce994..55e7051 100644
--- a/src/changes/changes.xml
+++ b/src/changes/changes.xml
@@ -74,6 +74,12 @@
<action issue="LOG4J2-2165" dev="ggregory" type="update">
Update Jackson from 2.9.2 to 2.9.3.
</action>
+ <action issue="LOG4J2-2179" dev="ggregory" type="add">
+ The MongoDB Appender should use a keys and values for a Log4j MapMessage.
+ </action>
+ <action issue="LOG4J2-2180" dev="ggregory" type="add">
+ Add a MongoDbProvider builder for and deprecate org.apache.logging.log4j.mongodb.MongoDbProvider.createNoSqlProvider().
+ </action>
</release>
<release version="2.10.0" date="2017-11-18" description="GA Release 2.10.0">
<action issue="LOG4J2-2120" dev="mikes" type="add" due-to="Carter Douglas Kozak ">
[2/2] logging-log4j2 git commit: [LOG4J2-2179] The MongoDB Appender
should use a keys and values for a Log4j MapMessage. [LOG4J2-2180] Add a
MongoDbProvider builder for and deprecate
org.apache.logging.log4j.mongodb.MongoDbProvider.createNoSqlProvider().
Posted by gg...@apache.org.
[LOG4J2-2179] The MongoDB Appender should use a keys and values for a
Log4j MapMessage.
[LOG4J2-2180] Add a MongoDbProvider builder for and deprecate
org.apache.logging.log4j.mongodb.MongoDbProvider.createNoSqlProvider().
Project: http://git-wip-us.apache.org/repos/asf/logging-log4j2/repo
Commit: http://git-wip-us.apache.org/repos/asf/logging-log4j2/commit/26fc9e07
Tree: http://git-wip-us.apache.org/repos/asf/logging-log4j2/tree/26fc9e07
Diff: http://git-wip-us.apache.org/repos/asf/logging-log4j2/diff/26fc9e07
Branch: refs/heads/master
Commit: 26fc9e0794c0e3a4f5c57ba5009ef31ebea9c960
Parents: ed600f7
Author: Gary Gregory <gg...@apache.org>
Authored: Wed Jan 10 19:19:51 2018 -0700
Committer: Gary Gregory <gg...@apache.org>
Committed: Wed Jan 10 19:19:51 2018 -0700
----------------------------------------------------------------------
.../log4j/core/appender/AbstractAppender.java | 11 +
.../core/appender/OutputStreamManager.java | 3 +-
.../appender/db/AbstractDatabaseAppender.java | 301 ++++-----
.../appender/db/AbstractDatabaseManager.java | 487 +++++++-------
.../appender/db/jdbc/JdbcDatabaseManager.java | 633 ++++++++++---------
.../appender/db/jpa/JpaDatabaseManager.java | 393 ++++++------
.../log4j/core/appender/mom/JmsAppender.java | 2 +-
.../log4j/core/appender/mom/JmsManager.java | 2 +-
.../core/appender/nosql/NoSqlAppender.java | 138 +++-
.../appender/nosql/NoSqlDatabaseManager.java | 33 +-
.../db/AbstractDatabaseAppenderTest.java | 4 +-
.../db/AbstractDatabaseManagerTest.java | 63 +-
.../nosql/NoSqlDatabaseManagerTest.java | 10 +-
.../test/AvailablePortSystemPropertyRule.java | 81 ---
.../AvailablePortSystemPropertyTestRule.java | 81 +++
log4j-mongodb/pom.xml | 6 +
.../apache/logging/log4j/mongodb/Java8Test.java | 48 ++
.../logging/log4j/mongodb/MongoDbAuthTest.java | 40 --
.../log4j/mongodb/MongoDbAuthTestJava8.java | 52 ++
.../log4j/mongodb/MongoDbCappedTest.java | 40 --
.../log4j/mongodb/MongoDbCappedTestJava8.java | 52 ++
.../mongodb/MongoDbMapMessageTestJava8.java | 74 +++
.../logging/log4j/mongodb/MongoDbTest.java | 40 --
.../logging/log4j/mongodb/MongoDbTestJava8.java | 52 ++
.../logging/log4j/mongodb/MongoDbTestRule.java | 139 ++++
.../mongodb/MongoDbTestTestRuleTestJava8.java | 69 ++
.../resources/log4j2-mongodb-map-message.xml | 23 +
src/changes/changes.xml | 6 +
28 files changed, 1734 insertions(+), 1149 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/26fc9e07/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/AbstractAppender.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/AbstractAppender.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/AbstractAppender.java
index 98bb240..57974bd 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/AbstractAppender.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/AbstractAppender.java
@@ -252,6 +252,17 @@ public abstract class AbstractAppender extends AbstractFilterable implements App
this.handler = handler;
}
+ /**
+ * Serializes the given event using the appender's layout if present.
+ *
+ * @param event
+ * the event to serialize.
+ * @return the serialized event or null if no layout is present.
+ */
+ protected Serializable toSerializable(final LogEvent event) {
+ return layout != null ? layout.toSerializable(event) : null;
+ }
+
@Override
public String toString() {
return name;
http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/26fc9e07/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/OutputStreamManager.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/OutputStreamManager.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/OutputStreamManager.java
index 51ef174..0873822 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/OutputStreamManager.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/OutputStreamManager.java
@@ -19,6 +19,7 @@ package org.apache.logging.log4j.core.appender;
import java.io.IOException;
import java.io.OutputStream;
import java.io.Serializable;
+import java.nio.Buffer;
import java.nio.ByteBuffer;
import java.util.Objects;
import java.util.concurrent.TimeUnit;
@@ -289,7 +290,7 @@ public class OutputStreamManager extends AbstractManager implements ByteBufferDe
* @since 2.6
*/
protected synchronized void flushBuffer(final ByteBuffer buf) {
- buf.flip();
+ ((Buffer) buf).flip();
if (buf.remaining() > 0) {
writeToDestination(buf.array(), buf.arrayOffset() + buf.position(), buf.remaining());
}
http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/26fc9e07/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/db/AbstractDatabaseAppender.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/db/AbstractDatabaseAppender.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/db/AbstractDatabaseAppender.java
index 38f412c..09798fd 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/db/AbstractDatabaseAppender.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/db/AbstractDatabaseAppender.java
@@ -1,142 +1,159 @@
-/*
- * 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.db;
-
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.locks.Lock;
-import java.util.concurrent.locks.ReadWriteLock;
-import java.util.concurrent.locks.ReentrantReadWriteLock;
-
-import org.apache.logging.log4j.LoggingException;
-import org.apache.logging.log4j.core.Filter;
-import org.apache.logging.log4j.core.Layout;
-import org.apache.logging.log4j.core.LogEvent;
-import org.apache.logging.log4j.core.appender.AbstractAppender;
-import org.apache.logging.log4j.core.appender.AppenderLoggingException;
-
-/**
- * An abstract Appender for writing events to a database of some type, be it relational or NoSQL. All database appenders
- * should inherit from this base appender. Three implementations are currently provided:
- * {@link org.apache.logging.log4j.core.appender.db.jdbc JDBC}, {@link org.apache.logging.log4j.core.appender.db.jpa
- * JPA}, and {@link org.apache.logging.log4j.core.appender.nosql NoSQL}.
- *
- * @param <T> Specifies which type of {@link AbstractDatabaseManager} this Appender requires.
- */
-public abstract class AbstractDatabaseAppender<T extends AbstractDatabaseManager> extends AbstractAppender {
-
- private final ReadWriteLock lock = new ReentrantReadWriteLock();
- private final Lock readLock = lock.readLock();
- private final Lock writeLock = lock.writeLock();
-
- private T manager;
-
- /**
- * Instantiates the base appender.
- *
- * @param name The appender name.
- * @param filter The filter, if any, to use.
- * @param ignoreExceptions If {@code true} exceptions encountered when appending events are logged; otherwise
- * they are propagated to the caller.
- * @param manager The matching {@link AbstractDatabaseManager} implementation.
- */
- protected AbstractDatabaseAppender(final String name, final Filter filter, final boolean ignoreExceptions,
- final T manager) {
- super(name, filter, null, ignoreExceptions);
- this.manager = manager;
- }
-
- /**
- * This always returns {@code null}, as database appenders do not use a single layout. The JPA and NoSQL appenders
- * do not use a layout at all. The JDBC appender has a layout-per-column pattern.
- *
- * @return {@code null}.
- */
- @Override
- public final Layout<LogEvent> getLayout() {
- return null;
- }
-
- /**
- * Returns the underlying manager in use within this appender.
- *
- * @return the manager.
- */
- public final T getManager() {
- return this.manager;
- }
-
- @Override
- public final void start() {
- if (this.getManager() == null) {
- LOGGER.error("No AbstractDatabaseManager set for the appender named [{}].", this.getName());
- }
- super.start();
- if (this.getManager() != null) {
- this.getManager().startup();
- }
- }
-
- @Override
- public boolean stop(final long timeout, final TimeUnit timeUnit) {
- setStopping();
- boolean stopped = super.stop(timeout, timeUnit, false);
- if (this.getManager() != null) {
- stopped &= this.getManager().stop(timeout, timeUnit);
- }
- setStopped();
- return stopped;
- }
-
- @Override
- public final void append(final LogEvent event) {
- this.readLock.lock();
- try {
- this.getManager().write(event);
- } catch (final LoggingException e) {
- LOGGER.error("Unable to write to database [{}] for appender [{}].", this.getManager().getName(),
- this.getName(), e);
- throw e;
- } catch (final Exception e) {
- LOGGER.error("Unable to write to database [{}] for appender [{}].", this.getManager().getName(),
- this.getName(), e);
- throw new AppenderLoggingException("Unable to write to database in appender: " + e.getMessage(), e);
- } finally {
- this.readLock.unlock();
- }
- }
-
- /**
- * Replaces the underlying manager in use within this appender. This can be useful for manually changing the way log
- * events are written to the database without losing buffered or in-progress events. The existing manager is
- * released only after the new manager has been installed. This method is thread-safe.
- *
- * @param manager The new manager to install.
- */
- protected final void replaceManager(final T manager) {
- this.writeLock.lock();
- try {
- final T old = this.getManager();
- if (!manager.isRunning()) {
- manager.startup();
- }
- this.manager = manager;
- old.close();
- } finally {
- this.writeLock.unlock();
- }
- }
-}
+/*
+ * 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.db;
+
+import java.io.Serializable;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReadWriteLock;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
+
+import org.apache.logging.log4j.LoggingException;
+import org.apache.logging.log4j.core.Filter;
+import org.apache.logging.log4j.core.Layout;
+import org.apache.logging.log4j.core.LogEvent;
+import org.apache.logging.log4j.core.appender.AbstractAppender;
+import org.apache.logging.log4j.core.appender.AppenderLoggingException;
+
+/**
+ * An abstract Appender for writing events to a database of some type, be it relational or NoSQL. All database appenders
+ * should inherit from this base appender. Three implementations are currently provided:
+ * {@link org.apache.logging.log4j.core.appender.db.jdbc JDBC}, {@link org.apache.logging.log4j.core.appender.db.jpa
+ * JPA}, and {@link org.apache.logging.log4j.core.appender.nosql NoSQL}.
+ *
+ * @param <T> Specifies which type of {@link AbstractDatabaseManager} this Appender requires.
+ */
+public abstract class AbstractDatabaseAppender<T extends AbstractDatabaseManager> extends AbstractAppender {
+
+ private final ReadWriteLock lock = new ReentrantReadWriteLock();
+ private final Lock readLock = lock.readLock();
+ private final Lock writeLock = lock.writeLock();
+
+ private T manager;
+
+ /**
+ * Instantiates the base appender.
+ *
+ * @param name The appender name.
+ * @param filter The filter, if any, to use.
+ * @param ignoreExceptions If {@code true} exceptions encountered when appending events are logged; otherwise
+ * they are propagated to the caller.
+ * @param manager The matching {@link AbstractDatabaseManager} implementation.
+ */
+ protected AbstractDatabaseAppender(final String name, final Filter filter, final boolean ignoreExceptions,
+ final T manager) {
+ super(name, filter, null, ignoreExceptions);
+ this.manager = manager;
+ }
+
+ /**
+ * Instantiates the base appender.
+ *
+ * @param name The appender name.
+ * @param filter The filter, if any, to use.
+ * @param layout The layout to use to format the event.
+ * @param ignoreExceptions If {@code true} exceptions encountered when appending events are logged; otherwise
+ * they are propagated to the caller.
+ * @param manager The matching {@link AbstractDatabaseManager} implementation.
+ */
+ protected AbstractDatabaseAppender(final String name, final Filter filter,
+ final Layout<? extends Serializable> layout, final boolean ignoreExceptions, final T manager) {
+ super(name, filter, layout, ignoreExceptions);
+ this.manager = manager;
+ }
+
+ /**
+ * This always returns {@code null}, as database appenders do not use a single layout. The JPA and NoSQL appenders
+ * do not use a layout at all. The JDBC appender has a layout-per-column pattern.
+ *
+ * @return {@code null}.
+ */
+ @Override
+ public final Layout<LogEvent> getLayout() {
+ return null;
+ }
+
+ /**
+ * Returns the underlying manager in use within this appender.
+ *
+ * @return the manager.
+ */
+ public final T getManager() {
+ return this.manager;
+ }
+
+ @Override
+ public final void start() {
+ if (this.getManager() == null) {
+ LOGGER.error("No AbstractDatabaseManager set for the appender named [{}].", this.getName());
+ }
+ super.start();
+ if (this.getManager() != null) {
+ this.getManager().startup();
+ }
+ }
+
+ @Override
+ public boolean stop(final long timeout, final TimeUnit timeUnit) {
+ setStopping();
+ boolean stopped = super.stop(timeout, timeUnit, false);
+ if (this.getManager() != null) {
+ stopped &= this.getManager().stop(timeout, timeUnit);
+ }
+ setStopped();
+ return stopped;
+ }
+
+ @Override
+ public final void append(final LogEvent event) {
+ this.readLock.lock();
+ try {
+ this.getManager().write(event, toSerializable(event));
+ } catch (final LoggingException e) {
+ LOGGER.error("Unable to write to database [{}] for appender [{}].", this.getManager().getName(),
+ this.getName(), e);
+ throw e;
+ } catch (final Exception e) {
+ LOGGER.error("Unable to write to database [{}] for appender [{}].", this.getManager().getName(),
+ this.getName(), e);
+ throw new AppenderLoggingException("Unable to write to database in appender: " + e.getMessage(), e);
+ } finally {
+ this.readLock.unlock();
+ }
+ }
+
+ /**
+ * Replaces the underlying manager in use within this appender. This can be useful for manually changing the way log
+ * events are written to the database without losing buffered or in-progress events. The existing manager is
+ * released only after the new manager has been installed. This method is thread-safe.
+ *
+ * @param manager The new manager to install.
+ */
+ protected final void replaceManager(final T manager) {
+ this.writeLock.lock();
+ try {
+ final T old = this.getManager();
+ if (!manager.isRunning()) {
+ manager.startup();
+ }
+ this.manager = manager;
+ old.close();
+ } finally {
+ this.writeLock.unlock();
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/26fc9e07/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/db/AbstractDatabaseManager.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/db/AbstractDatabaseManager.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/db/AbstractDatabaseManager.java
index b8b9899..54c33d1 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/db/AbstractDatabaseManager.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/db/AbstractDatabaseManager.java
@@ -1,232 +1,255 @@
-/*
- * 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.db;
-
-import java.io.Flushable;
-import java.util.ArrayList;
-import java.util.concurrent.TimeUnit;
-
-import org.apache.logging.log4j.core.LogEvent;
-import org.apache.logging.log4j.core.appender.AbstractManager;
-import org.apache.logging.log4j.core.appender.ManagerFactory;
-
-/**
- * Manager that allows database appenders to have their configuration reloaded without losing events.
- */
-public abstract class AbstractDatabaseManager extends AbstractManager implements Flushable {
- private final ArrayList<LogEvent> buffer;
- private final int bufferSize;
-
- private boolean running = false;
-
- /**
- * Instantiates the base manager.
- *
- * @param name The manager name, which should include any configuration details that one might want to be able to
- * reconfigure at runtime, such as database name, username, (hashed) password, etc.
- * @param bufferSize The size of the log event buffer.
- */
- protected AbstractDatabaseManager(final String name, final int bufferSize) {
- super(null, name);
- this.bufferSize = bufferSize;
- this.buffer = new ArrayList<>(bufferSize + 1);
- }
-
- /**
- * Implementations should implement this method to perform any proprietary startup operations. This method will
- * never be called twice on the same instance. It is safe to throw any exceptions from this method. This method
- * does not necessarily connect to the database, as it is generally unreliable to connect once and use the same
- * connection for hours.
- */
- protected abstract void startupInternal() throws Exception;
-
- /**
- * This method is called within the appender when the appender is started. If it has not already been called, it
- * calls {@link #startupInternal()} and catches any exceptions it might throw.
- */
- public final synchronized void startup() {
- if (!this.isRunning()) {
- try {
- this.startupInternal();
- this.running = true;
- } catch (final Exception e) {
- logError("Could not perform database startup operations", e);
- }
- }
- }
-
- /**
- * Implementations should implement this method to perform any proprietary disconnection / shutdown operations. This
- * method will never be called twice on the same instance, and it will only be called <em>after</em>
- * {@link #startupInternal()}. It is safe to throw any exceptions from this method. This method does not
- * necessarily disconnect from the database for the same reasons outlined in {@link #startupInternal()}.
- * @return true if all resources were closed normally, false otherwise.
- */
- protected abstract boolean shutdownInternal() throws Exception;
-
- /**
- * This method is called from the {@link #close()} method when the appender is stopped or the appender's manager
- * is replaced. If it has not already been called, it calls {@link #shutdownInternal()} and catches any exceptions
- * it might throw.
- * @return true if all resources were closed normally, false otherwise.
- */
- public final synchronized boolean shutdown() {
- boolean closed = true;
- this.flush();
- if (this.isRunning()) {
- try {
- closed &= this.shutdownInternal();
- } catch (final Exception e) {
- logWarn("Caught exception while performing database shutdown operations", e);
- closed = false;
- } finally {
- this.running = false;
- }
- }
- return closed;
- }
-
- /**
- * Indicates whether the manager is currently connected {@link #startup()} has been called and {@link #shutdown()}
- * has not been called).
- *
- * @return {@code true} if the manager is connected.
- */
- public final boolean isRunning() {
- return this.running;
- }
-
- /**
- * Connects to the database and starts a transaction (if applicable). With buffering enabled, this is called when
- * flushing the buffer begins, before the first call to {@link #writeInternal}. With buffering disabled, this is
- * called immediately before every invocation of {@link #writeInternal}.
- */
- protected abstract void connectAndStart();
-
- /**
- * Performs the actual writing of the event in an implementation-specific way. This method is called immediately
- * from {@link #write(LogEvent)} if buffering is off, or from {@link #flush()} if the buffer has reached its limit.
- *
- * @param event The event to write to the database.
- */
- protected abstract void writeInternal(LogEvent event);
-
- /**
- * Commits any active transaction (if applicable) and disconnects from the database (returns the connection to the
- * connection pool). With buffering enabled, this is called when flushing the buffer completes, after the last call
- * to {@link #writeInternal}. With buffering disabled, this is called immediately after every invocation of
- * {@link #writeInternal}.
- * @return true if all resources were closed normally, false otherwise.
- */
- protected abstract boolean commitAndClose();
-
- /**
- * This method is called automatically when the buffer size reaches its maximum or at the beginning of a call to
- * {@link #shutdown()}. It can also be called manually to flush events to the database.
- */
- @Override
- public final synchronized void flush() {
- if (this.isRunning() && this.buffer.size() > 0) {
- this.connectAndStart();
- try {
- for (final LogEvent event : this.buffer) {
- this.writeInternal(event);
- }
- } finally {
- this.commitAndClose();
- // not sure if this should be done when writing the events failed
- this.buffer.clear();
- }
- }
- }
-
- /**
- * This method manages buffering and writing of events.
- *
- * @param event The event to write to the database.
- */
- public final synchronized void write(final LogEvent event) {
- if (this.bufferSize > 0) {
- this.buffer.add(event.toImmutable());
- if (this.buffer.size() >= this.bufferSize || event.isEndOfBatch()) {
- this.flush();
- }
- } else {
- this.connectAndStart();
- try {
- this.writeInternal(event);
- } finally {
- this.commitAndClose();
- }
- }
- }
-
- @Override
- public final boolean releaseSub(final long timeout, final TimeUnit timeUnit) {
- return this.shutdown();
- }
-
- @Override
- public final String toString() {
- return this.getName();
- }
-
- /**
- * Implementations should define their own getManager method and call this method from that to create or get
- * existing managers.
- *
- * @param name The manager name, which should include any configuration details that one might want to be able to
- * reconfigure at runtime, such as database name, username, (hashed) password, etc.
- * @param data The concrete instance of {@link AbstractFactoryData} appropriate for the given manager.
- * @param factory A factory instance for creating the appropriate manager.
- * @param <M> The concrete manager type.
- * @param <T> The concrete {@link AbstractFactoryData} type.
- * @return a new or existing manager of the specified type and name.
- */
- protected static <M extends AbstractDatabaseManager, T extends AbstractFactoryData> M getManager(
- final String name, final T data, final ManagerFactory<M, T> factory
- ) {
- return AbstractManager.getManager(name, factory, data);
- }
-
- /**
- * Implementations should extend this class for passing data between the getManager method and the manager factory
- * class.
- */
- protected abstract static class AbstractFactoryData {
- private final int bufferSize;
-
- /**
- * Constructs the base factory data.
- *
- * @param bufferSize The size of the buffer.
- */
- protected AbstractFactoryData(final int bufferSize) {
- this.bufferSize = bufferSize;
- }
-
- /**
- * Gets the buffer size.
- *
- * @return the buffer size.
- */
- public int getBufferSize() {
- return bufferSize;
- }
- }
-}
+/*
+ * 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.db;
+
+import java.io.Flushable;
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.concurrent.TimeUnit;
+
+import org.apache.logging.log4j.core.LogEvent;
+import org.apache.logging.log4j.core.appender.AbstractManager;
+import org.apache.logging.log4j.core.appender.ManagerFactory;
+
+/**
+ * Manager that allows database appenders to have their configuration reloaded without losing events.
+ */
+public abstract class AbstractDatabaseManager extends AbstractManager implements Flushable {
+ private final ArrayList<LogEvent> buffer;
+ private final int bufferSize;
+
+ private boolean running = false;
+
+ /**
+ * Instantiates the base manager.
+ *
+ * @param name The manager name, which should include any configuration details that one might want to be able to
+ * reconfigure at runtime, such as database name, username, (hashed) password, etc.
+ * @param bufferSize The size of the log event buffer.
+ */
+ protected AbstractDatabaseManager(final String name, final int bufferSize) {
+ super(null, name);
+ this.bufferSize = bufferSize;
+ this.buffer = new ArrayList<>(bufferSize + 1);
+ }
+
+ /**
+ * Implementations should implement this method to perform any proprietary startup operations. This method will
+ * never be called twice on the same instance. It is safe to throw any exceptions from this method. This method
+ * does not necessarily connect to the database, as it is generally unreliable to connect once and use the same
+ * connection for hours.
+ */
+ protected abstract void startupInternal() throws Exception;
+
+ /**
+ * This method is called within the appender when the appender is started. If it has not already been called, it
+ * calls {@link #startupInternal()} and catches any exceptions it might throw.
+ */
+ public final synchronized void startup() {
+ if (!this.isRunning()) {
+ try {
+ this.startupInternal();
+ this.running = true;
+ } catch (final Exception e) {
+ logError("Could not perform database startup operations", e);
+ }
+ }
+ }
+
+ /**
+ * Implementations should implement this method to perform any proprietary disconnection / shutdown operations. This
+ * method will never be called twice on the same instance, and it will only be called <em>after</em>
+ * {@link #startupInternal()}. It is safe to throw any exceptions from this method. This method does not
+ * necessarily disconnect from the database for the same reasons outlined in {@link #startupInternal()}.
+ * @return true if all resources were closed normally, false otherwise.
+ */
+ protected abstract boolean shutdownInternal() throws Exception;
+
+ /**
+ * This method is called from the {@link #close()} method when the appender is stopped or the appender's manager
+ * is replaced. If it has not already been called, it calls {@link #shutdownInternal()} and catches any exceptions
+ * it might throw.
+ * @return true if all resources were closed normally, false otherwise.
+ */
+ public final synchronized boolean shutdown() {
+ boolean closed = true;
+ this.flush();
+ if (this.isRunning()) {
+ try {
+ closed &= this.shutdownInternal();
+ } catch (final Exception e) {
+ logWarn("Caught exception while performing database shutdown operations", e);
+ closed = false;
+ } finally {
+ this.running = false;
+ }
+ }
+ return closed;
+ }
+
+ /**
+ * Indicates whether the manager is currently connected {@link #startup()} has been called and {@link #shutdown()}
+ * has not been called).
+ *
+ * @return {@code true} if the manager is connected.
+ */
+ public final boolean isRunning() {
+ return this.running;
+ }
+
+ /**
+ * Connects to the database and starts a transaction (if applicable). With buffering enabled, this is called when
+ * flushing the buffer begins, before the first call to {@link #writeInternal}. With buffering disabled, this is
+ * called immediately before every invocation of {@link #writeInternal}.
+ */
+ protected abstract void connectAndStart();
+
+ /**
+ * Performs the actual writing of the event in an implementation-specific way. This method is called immediately
+ * from {@link #write(LogEvent, Serializable)} if buffering is off, or from {@link #flush()} if the buffer has reached its limit.
+ *
+ * @param event The event to write to the database.
+ * @deprecated Use {@link #writeInternal(LogEvent, Serializable)}.
+ */
+ @Deprecated
+ protected abstract void writeInternal(LogEvent event);
+
+ /**
+ * Performs the actual writing of the event in an implementation-specific way. This method is called immediately
+ * from {@link #write(LogEvent, Serializable)} if buffering is off, or from {@link #flush()} if the buffer has reached its limit.
+ *
+ * @param event The event to write to the database.
+ */
+ protected abstract void writeInternal(LogEvent event, Serializable serializable);
+
+ /**
+ * Commits any active transaction (if applicable) and disconnects from the database (returns the connection to the
+ * connection pool). With buffering enabled, this is called when flushing the buffer completes, after the last call
+ * to {@link #writeInternal}. With buffering disabled, this is called immediately after every invocation of
+ * {@link #writeInternal}.
+ * @return true if all resources were closed normally, false otherwise.
+ */
+ protected abstract boolean commitAndClose();
+
+ /**
+ * This method is called automatically when the buffer size reaches its maximum or at the beginning of a call to
+ * {@link #shutdown()}. It can also be called manually to flush events to the database.
+ */
+ @Override
+ public final synchronized void flush() {
+ if (this.isRunning() && this.buffer.size() > 0) {
+ this.connectAndStart();
+ try {
+ for (final LogEvent event : this.buffer) {
+ this.writeInternal(event);
+ }
+ } finally {
+ this.commitAndClose();
+ // not sure if this should be done when writing the events failed
+ this.buffer.clear();
+ }
+ }
+ }
+
+ /**
+ * This method manages buffering and writing of events.
+ *
+ * @param event The event to write to the database.
+ * @deprecated since 2.10.1 Use {@link #write(LogEvent, Serializable)}.
+ */
+ @Deprecated
+ public final synchronized void write(final LogEvent event) {
+ write(event, null);
+ }
+
+ /**
+ * This method manages buffering and writing of events.
+ *
+ * @param event The event to write to the database.
+ * @param serializable Serializable event
+ */
+ public final synchronized void write(final LogEvent event, final Serializable serializable) {
+ if (this.bufferSize > 0) {
+ this.buffer.add(event.toImmutable());
+ if (this.buffer.size() >= this.bufferSize || event.isEndOfBatch()) {
+ this.flush();
+ }
+ } else {
+ this.connectAndStart();
+ try {
+ this.writeInternal(event, serializable);
+ } finally {
+ this.commitAndClose();
+ }
+ }
+ }
+
+ @Override
+ public final boolean releaseSub(final long timeout, final TimeUnit timeUnit) {
+ return this.shutdown();
+ }
+
+ @Override
+ public final String toString() {
+ return this.getName();
+ }
+
+ /**
+ * Implementations should define their own getManager method and call this method from that to create or get
+ * existing managers.
+ *
+ * @param name The manager name, which should include any configuration details that one might want to be able to
+ * reconfigure at runtime, such as database name, username, (hashed) password, etc.
+ * @param data The concrete instance of {@link AbstractFactoryData} appropriate for the given manager.
+ * @param factory A factory instance for creating the appropriate manager.
+ * @param <M> The concrete manager type.
+ * @param <T> The concrete {@link AbstractFactoryData} type.
+ * @return a new or existing manager of the specified type and name.
+ */
+ protected static <M extends AbstractDatabaseManager, T extends AbstractFactoryData> M getManager(
+ final String name, final T data, final ManagerFactory<M, T> factory
+ ) {
+ return AbstractManager.getManager(name, factory, data);
+ }
+
+ /**
+ * Implementations should extend this class for passing data between the getManager method and the manager factory
+ * class.
+ */
+ protected abstract static class AbstractFactoryData {
+ private final int bufferSize;
+
+ /**
+ * Constructs the base factory data.
+ *
+ * @param bufferSize The size of the buffer.
+ */
+ protected AbstractFactoryData(final int bufferSize) {
+ this.bufferSize = bufferSize;
+ }
+
+ /**
+ * Gets the buffer size.
+ *
+ * @return the buffer size.
+ */
+ public int getBufferSize() {
+ return bufferSize;
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/26fc9e07/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/db/jdbc/JdbcDatabaseManager.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/db/jdbc/JdbcDatabaseManager.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/db/jdbc/JdbcDatabaseManager.java
index 2d80f70..a652c2c 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/db/jdbc/JdbcDatabaseManager.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/db/jdbc/JdbcDatabaseManager.java
@@ -1,313 +1,320 @@
-/*
- * 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.db.jdbc;
-
-import java.io.StringReader;
-import java.sql.Clob;
-import java.sql.Connection;
-import java.sql.DatabaseMetaData;
-import java.sql.NClob;
-import java.sql.PreparedStatement;
-import java.sql.SQLException;
-import java.sql.Timestamp;
-import java.sql.Types;
-import java.util.ArrayList;
-import java.util.Date;
-import java.util.List;
-
-import org.apache.logging.log4j.core.LogEvent;
-import org.apache.logging.log4j.core.appender.AppenderLoggingException;
-import org.apache.logging.log4j.core.appender.ManagerFactory;
-import org.apache.logging.log4j.core.appender.db.AbstractDatabaseManager;
-import org.apache.logging.log4j.core.appender.db.ColumnMapping;
-import org.apache.logging.log4j.core.config.plugins.convert.DateTypeConverter;
-import org.apache.logging.log4j.core.config.plugins.convert.TypeConverters;
-import org.apache.logging.log4j.core.util.Closer;
-import org.apache.logging.log4j.spi.ThreadContextMap;
-import org.apache.logging.log4j.spi.ThreadContextStack;
-import org.apache.logging.log4j.util.ReadOnlyStringMap;
-import org.apache.logging.log4j.util.Strings;
-
-/**
- * An {@link AbstractDatabaseManager} implementation for relational databases accessed via JDBC.
- */
-public final class JdbcDatabaseManager extends AbstractDatabaseManager {
-
- private static final JdbcDatabaseManagerFactory INSTANCE = new JdbcDatabaseManagerFactory();
-
- // NOTE: prepared statements are prepared in this order: column mappings, then column configs
- private final List<ColumnMapping> columnMappings;
- private final List<ColumnConfig> columnConfigs;
- private final ConnectionSource connectionSource;
- private final String sqlStatement;
-
- private Connection connection;
- private PreparedStatement statement;
- private boolean isBatchSupported;
-
- private JdbcDatabaseManager(final String name, final int bufferSize, final ConnectionSource connectionSource,
- final String sqlStatement, final List<ColumnConfig> columnConfigs,
- final List<ColumnMapping> columnMappings) {
- super(name, bufferSize);
- this.connectionSource = connectionSource;
- this.sqlStatement = sqlStatement;
- this.columnConfigs = columnConfigs;
- this.columnMappings = columnMappings;
- }
-
- @Override
- protected void startupInternal() throws Exception {
- this.connection = this.connectionSource.getConnection();
- final DatabaseMetaData metaData = this.connection.getMetaData();
- this.isBatchSupported = metaData.supportsBatchUpdates();
- Closer.closeSilently(this.connection);
- }
-
- @Override
- protected boolean shutdownInternal() {
- if (this.connection != null || this.statement != null) {
- return this.commitAndClose();
- }
- return true;
- }
-
- @Override
- protected void connectAndStart() {
- try {
- this.connection = this.connectionSource.getConnection();
- this.connection.setAutoCommit(false);
- this.statement = this.connection.prepareStatement(this.sqlStatement);
- } catch (final SQLException e) {
- throw new AppenderLoggingException(
- "Cannot write logging event or flush buffer; JDBC manager cannot connect to the database.", e
- );
- }
- }
-
- @Override
- protected void writeInternal(final LogEvent event) {
- StringReader reader = null;
- try {
- if (!this.isRunning() || this.connection == null || this.connection.isClosed() || this.statement == null
- || this.statement.isClosed()) {
- throw new AppenderLoggingException(
- "Cannot write logging event; JDBC manager not connected to the database.");
- }
-
- int i = 1;
- for (final ColumnMapping mapping : this.columnMappings) {
- if (ThreadContextMap.class.isAssignableFrom(mapping.getType())
- || ReadOnlyStringMap.class.isAssignableFrom(mapping.getType())) {
- this.statement.setObject(i++, event.getContextData().toMap());
- } else if (ThreadContextStack.class.isAssignableFrom(mapping.getType())) {
- this.statement.setObject(i++, event.getContextStack().asList());
- } else if (Date.class.isAssignableFrom(mapping.getType())) {
- this.statement.setObject(i++,
- DateTypeConverter.fromMillis(event.getTimeMillis(), mapping.getType().asSubclass(Date.class)));
- } else if (Clob.class.isAssignableFrom(mapping.getType())) {
- this.statement.setClob(i++, new StringReader(mapping.getLayout().toSerializable(event)));
- } else if (NClob.class.isAssignableFrom(mapping.getType())) {
- this.statement.setNClob(i++, new StringReader(mapping.getLayout().toSerializable(event)));
- } else {
- final Object value = TypeConverters.convert(mapping.getLayout().toSerializable(event),
- mapping.getType(), null);
- if (value == null) {
- this.statement.setNull(i++, Types.NULL);
- } else {
- this.statement.setObject(i++, value);
- }
- }
- }
- for (final ColumnConfig column : this.columnConfigs) {
- if (column.isEventTimestamp()) {
- this.statement.setTimestamp(i++, new Timestamp(event.getTimeMillis()));
- } else if (column.isClob()) {
- reader = new StringReader(column.getLayout().toSerializable(event));
- if (column.isUnicode()) {
- this.statement.setNClob(i++, reader);
- } else {
- this.statement.setClob(i++, reader);
- }
- } else if (column.isUnicode()) {
- this.statement.setNString(i++, column.getLayout().toSerializable(event));
- } else {
- this.statement.setString(i++, column.getLayout().toSerializable(event));
- }
- }
-
- if (this.isBatchSupported) {
- this.statement.addBatch();
- } else if (this.statement.executeUpdate() == 0) {
- throw new AppenderLoggingException(
- "No records inserted in database table for log event in JDBC manager.");
- }
- } catch (final SQLException e) {
- throw new AppenderLoggingException("Failed to insert record for log event in JDBC manager: " +
- e.getMessage(), e);
- } finally {
- Closer.closeSilently(reader);
- }
- }
-
- @Override
- protected boolean commitAndClose() {
- boolean closed = true;
- try {
- if (this.connection != null && !this.connection.isClosed()) {
- if (this.isBatchSupported) {
- this.statement.executeBatch();
- }
- this.connection.commit();
- }
- } catch (final SQLException e) {
- throw new AppenderLoggingException("Failed to commit transaction logging event or flushing buffer.", e);
- } finally {
- try {
- Closer.close(this.statement);
- } catch (final Exception e) {
- logWarn("Failed to close SQL statement logging event or flushing buffer", e);
- closed = false;
- } finally {
- this.statement = null;
- }
-
- try {
- Closer.close(this.connection);
- } catch (final Exception e) {
- logWarn("Failed to close database connection logging event or flushing buffer", e);
- closed = false;
- } finally {
- this.connection = null;
- }
- }
- return closed;
- }
-
- /**
- * Creates a JDBC manager for use within the {@link JdbcAppender}, or returns a suitable one if it already exists.
- *
- * @param name The name of the manager, which should include connection details and hashed passwords where possible.
- * @param bufferSize The size of the log event buffer.
- * @param connectionSource The source for connections to the database.
- * @param tableName The name of the database table to insert log events into.
- * @param columnConfigs Configuration information about the log table columns.
- * @return a new or existing JDBC manager as applicable.
- * @deprecated use {@link #getManager(String, int, ConnectionSource, String, ColumnConfig[], ColumnMapping[])}
- */
- @Deprecated
- public static JdbcDatabaseManager getJDBCDatabaseManager(final String name, final int bufferSize,
- final ConnectionSource connectionSource,
- final String tableName,
- final ColumnConfig[] columnConfigs) {
-
- return getManager(name,
- new FactoryData(bufferSize, connectionSource, tableName, columnConfigs, new ColumnMapping[0]),
- getFactory());
- }
-
- /**
- * Creates a JDBC manager for use within the {@link JdbcAppender}, or returns a suitable one if it already exists.
- *
- * @param name The name of the manager, which should include connection details and hashed passwords where possible.
- * @param bufferSize The size of the log event buffer.
- * @param connectionSource The source for connections to the database.
- * @param tableName The name of the database table to insert log events into.
- * @param columnConfigs Configuration information about the log table columns.
- * @param columnMappings column mapping configuration (including type conversion).
- * @return a new or existing JDBC manager as applicable.
- */
- public static JdbcDatabaseManager getManager(final String name,
- final int bufferSize,
- final ConnectionSource connectionSource,
- final String tableName,
- final ColumnConfig[] columnConfigs,
- final ColumnMapping[] columnMappings) {
- return getManager(name, new FactoryData(bufferSize, connectionSource, tableName, columnConfigs, columnMappings),
- getFactory());
- }
-
- private static JdbcDatabaseManagerFactory getFactory() {
- return INSTANCE;
- }
-
- /**
- * Encapsulates data that {@link JdbcDatabaseManagerFactory} uses to create managers.
- */
- private static final class FactoryData extends AbstractDatabaseManager.AbstractFactoryData {
- private final ConnectionSource connectionSource;
- private final String tableName;
- private final ColumnConfig[] columnConfigs;
- private final ColumnMapping[] columnMappings;
-
- protected FactoryData(final int bufferSize, final ConnectionSource connectionSource, final String tableName,
- final ColumnConfig[] columnConfigs, final ColumnMapping[] columnMappings) {
- super(bufferSize);
- this.connectionSource = connectionSource;
- this.tableName = tableName;
- this.columnConfigs = columnConfigs;
- this.columnMappings = columnMappings;
- }
- }
-
- /**
- * Creates managers.
- */
- private static final class JdbcDatabaseManagerFactory implements ManagerFactory<JdbcDatabaseManager, FactoryData> {
- @Override
- public JdbcDatabaseManager createManager(final String name, final FactoryData data) {
- final StringBuilder sb = new StringBuilder("INSERT INTO ").append(data.tableName).append(" (");
- // so this gets a little more complicated now that there are two ways to configure column mappings, but
- // both mappings follow the same exact pattern for the prepared statement
- for (final ColumnMapping mapping : data.columnMappings) {
- sb.append(mapping.getName()).append(',');
- }
- for (final ColumnConfig config : data.columnConfigs) {
- sb.append(config.getColumnName()).append(',');
- }
- // at least one of those arrays is guaranteed to be non-empty
- sb.setCharAt(sb.length() - 1, ')');
- sb.append(" VALUES (");
- final List<ColumnMapping> columnMappings = new ArrayList<>(data.columnMappings.length);
- for (final ColumnMapping mapping : data.columnMappings) {
- if (Strings.isNotEmpty(mapping.getLiteralValue())) {
- sb.append(mapping.getLiteralValue());
- } else {
- sb.append('?');
- columnMappings.add(mapping);
- }
- sb.append(',');
- }
- final List<ColumnConfig> columnConfigs = new ArrayList<>(data.columnConfigs.length);
- for (final ColumnConfig config : data.columnConfigs) {
- if (Strings.isNotEmpty(config.getLiteralValue())) {
- sb.append(config.getLiteralValue());
- } else {
- sb.append('?');
- columnConfigs.add(config);
- }
- sb.append(',');
- }
- // at least one of those arrays is guaranteed to be non-empty
- sb.setCharAt(sb.length() - 1, ')');
- final String sqlStatement = sb.toString();
-
- return new JdbcDatabaseManager(name, data.getBufferSize(), data.connectionSource, sqlStatement,
- columnConfigs, columnMappings);
- }
- }
-
-}
+/*
+ * 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.db.jdbc;
+
+import java.io.Serializable;
+import java.io.StringReader;
+import java.sql.Clob;
+import java.sql.Connection;
+import java.sql.DatabaseMetaData;
+import java.sql.NClob;
+import java.sql.PreparedStatement;
+import java.sql.SQLException;
+import java.sql.Timestamp;
+import java.sql.Types;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+
+import org.apache.logging.log4j.core.LogEvent;
+import org.apache.logging.log4j.core.appender.AppenderLoggingException;
+import org.apache.logging.log4j.core.appender.ManagerFactory;
+import org.apache.logging.log4j.core.appender.db.AbstractDatabaseManager;
+import org.apache.logging.log4j.core.appender.db.ColumnMapping;
+import org.apache.logging.log4j.core.config.plugins.convert.DateTypeConverter;
+import org.apache.logging.log4j.core.config.plugins.convert.TypeConverters;
+import org.apache.logging.log4j.core.util.Closer;
+import org.apache.logging.log4j.spi.ThreadContextMap;
+import org.apache.logging.log4j.spi.ThreadContextStack;
+import org.apache.logging.log4j.util.ReadOnlyStringMap;
+import org.apache.logging.log4j.util.Strings;
+
+/**
+ * An {@link AbstractDatabaseManager} implementation for relational databases accessed via JDBC.
+ */
+public final class JdbcDatabaseManager extends AbstractDatabaseManager {
+
+ private static final JdbcDatabaseManagerFactory INSTANCE = new JdbcDatabaseManagerFactory();
+
+ // NOTE: prepared statements are prepared in this order: column mappings, then column configs
+ private final List<ColumnMapping> columnMappings;
+ private final List<ColumnConfig> columnConfigs;
+ private final ConnectionSource connectionSource;
+ private final String sqlStatement;
+
+ private Connection connection;
+ private PreparedStatement statement;
+ private boolean isBatchSupported;
+
+ private JdbcDatabaseManager(final String name, final int bufferSize, final ConnectionSource connectionSource,
+ final String sqlStatement, final List<ColumnConfig> columnConfigs,
+ final List<ColumnMapping> columnMappings) {
+ super(name, bufferSize);
+ this.connectionSource = connectionSource;
+ this.sqlStatement = sqlStatement;
+ this.columnConfigs = columnConfigs;
+ this.columnMappings = columnMappings;
+ }
+
+ @Override
+ protected void startupInternal() throws Exception {
+ this.connection = this.connectionSource.getConnection();
+ final DatabaseMetaData metaData = this.connection.getMetaData();
+ this.isBatchSupported = metaData.supportsBatchUpdates();
+ Closer.closeSilently(this.connection);
+ }
+
+ @Override
+ protected boolean shutdownInternal() {
+ if (this.connection != null || this.statement != null) {
+ return this.commitAndClose();
+ }
+ return true;
+ }
+
+ @Override
+ protected void connectAndStart() {
+ try {
+ this.connection = this.connectionSource.getConnection();
+ this.connection.setAutoCommit(false);
+ this.statement = this.connection.prepareStatement(this.sqlStatement);
+ } catch (final SQLException e) {
+ throw new AppenderLoggingException(
+ "Cannot write logging event or flush buffer; JDBC manager cannot connect to the database.", e
+ );
+ }
+ }
+
+ @Deprecated
+ @Override
+ protected void writeInternal(final LogEvent event) {
+ writeInternal(event, null);
+ }
+
+ @Override
+ protected void writeInternal(final LogEvent event, final Serializable serializable) {
+ StringReader reader = null;
+ try {
+ if (!this.isRunning() || this.connection == null || this.connection.isClosed() || this.statement == null
+ || this.statement.isClosed()) {
+ throw new AppenderLoggingException(
+ "Cannot write logging event; JDBC manager not connected to the database.");
+ }
+
+ int i = 1;
+ for (final ColumnMapping mapping : this.columnMappings) {
+ if (ThreadContextMap.class.isAssignableFrom(mapping.getType())
+ || ReadOnlyStringMap.class.isAssignableFrom(mapping.getType())) {
+ this.statement.setObject(i++, event.getContextData().toMap());
+ } else if (ThreadContextStack.class.isAssignableFrom(mapping.getType())) {
+ this.statement.setObject(i++, event.getContextStack().asList());
+ } else if (Date.class.isAssignableFrom(mapping.getType())) {
+ this.statement.setObject(i++,
+ DateTypeConverter.fromMillis(event.getTimeMillis(), mapping.getType().asSubclass(Date.class)));
+ } else if (Clob.class.isAssignableFrom(mapping.getType())) {
+ this.statement.setClob(i++, new StringReader(mapping.getLayout().toSerializable(event)));
+ } else if (NClob.class.isAssignableFrom(mapping.getType())) {
+ this.statement.setNClob(i++, new StringReader(mapping.getLayout().toSerializable(event)));
+ } else {
+ final Object value = TypeConverters.convert(mapping.getLayout().toSerializable(event),
+ mapping.getType(), null);
+ if (value == null) {
+ this.statement.setNull(i++, Types.NULL);
+ } else {
+ this.statement.setObject(i++, value);
+ }
+ }
+ }
+ for (final ColumnConfig column : this.columnConfigs) {
+ if (column.isEventTimestamp()) {
+ this.statement.setTimestamp(i++, new Timestamp(event.getTimeMillis()));
+ } else if (column.isClob()) {
+ reader = new StringReader(column.getLayout().toSerializable(event));
+ if (column.isUnicode()) {
+ this.statement.setNClob(i++, reader);
+ } else {
+ this.statement.setClob(i++, reader);
+ }
+ } else if (column.isUnicode()) {
+ this.statement.setNString(i++, column.getLayout().toSerializable(event));
+ } else {
+ this.statement.setString(i++, column.getLayout().toSerializable(event));
+ }
+ }
+
+ if (this.isBatchSupported) {
+ this.statement.addBatch();
+ } else if (this.statement.executeUpdate() == 0) {
+ throw new AppenderLoggingException(
+ "No records inserted in database table for log event in JDBC manager.");
+ }
+ } catch (final SQLException e) {
+ throw new AppenderLoggingException("Failed to insert record for log event in JDBC manager: " +
+ e.getMessage(), e);
+ } finally {
+ Closer.closeSilently(reader);
+ }
+ }
+
+ @Override
+ protected boolean commitAndClose() {
+ boolean closed = true;
+ try {
+ if (this.connection != null && !this.connection.isClosed()) {
+ if (this.isBatchSupported) {
+ this.statement.executeBatch();
+ }
+ this.connection.commit();
+ }
+ } catch (final SQLException e) {
+ throw new AppenderLoggingException("Failed to commit transaction logging event or flushing buffer.", e);
+ } finally {
+ try {
+ Closer.close(this.statement);
+ } catch (final Exception e) {
+ logWarn("Failed to close SQL statement logging event or flushing buffer", e);
+ closed = false;
+ } finally {
+ this.statement = null;
+ }
+
+ try {
+ Closer.close(this.connection);
+ } catch (final Exception e) {
+ logWarn("Failed to close database connection logging event or flushing buffer", e);
+ closed = false;
+ } finally {
+ this.connection = null;
+ }
+ }
+ return closed;
+ }
+
+ /**
+ * Creates a JDBC manager for use within the {@link JdbcAppender}, or returns a suitable one if it already exists.
+ *
+ * @param name The name of the manager, which should include connection details and hashed passwords where possible.
+ * @param bufferSize The size of the log event buffer.
+ * @param connectionSource The source for connections to the database.
+ * @param tableName The name of the database table to insert log events into.
+ * @param columnConfigs Configuration information about the log table columns.
+ * @return a new or existing JDBC manager as applicable.
+ * @deprecated use {@link #getManager(String, int, ConnectionSource, String, ColumnConfig[], ColumnMapping[])}
+ */
+ @Deprecated
+ public static JdbcDatabaseManager getJDBCDatabaseManager(final String name, final int bufferSize,
+ final ConnectionSource connectionSource,
+ final String tableName,
+ final ColumnConfig[] columnConfigs) {
+
+ return getManager(name,
+ new FactoryData(bufferSize, connectionSource, tableName, columnConfigs, new ColumnMapping[0]),
+ getFactory());
+ }
+
+ /**
+ * Creates a JDBC manager for use within the {@link JdbcAppender}, or returns a suitable one if it already exists.
+ *
+ * @param name The name of the manager, which should include connection details and hashed passwords where possible.
+ * @param bufferSize The size of the log event buffer.
+ * @param connectionSource The source for connections to the database.
+ * @param tableName The name of the database table to insert log events into.
+ * @param columnConfigs Configuration information about the log table columns.
+ * @param columnMappings column mapping configuration (including type conversion).
+ * @return a new or existing JDBC manager as applicable.
+ */
+ public static JdbcDatabaseManager getManager(final String name,
+ final int bufferSize,
+ final ConnectionSource connectionSource,
+ final String tableName,
+ final ColumnConfig[] columnConfigs,
+ final ColumnMapping[] columnMappings) {
+ return getManager(name, new FactoryData(bufferSize, connectionSource, tableName, columnConfigs, columnMappings),
+ getFactory());
+ }
+
+ private static JdbcDatabaseManagerFactory getFactory() {
+ return INSTANCE;
+ }
+
+ /**
+ * Encapsulates data that {@link JdbcDatabaseManagerFactory} uses to create managers.
+ */
+ private static final class FactoryData extends AbstractDatabaseManager.AbstractFactoryData {
+ private final ConnectionSource connectionSource;
+ private final String tableName;
+ private final ColumnConfig[] columnConfigs;
+ private final ColumnMapping[] columnMappings;
+
+ protected FactoryData(final int bufferSize, final ConnectionSource connectionSource, final String tableName,
+ final ColumnConfig[] columnConfigs, final ColumnMapping[] columnMappings) {
+ super(bufferSize);
+ this.connectionSource = connectionSource;
+ this.tableName = tableName;
+ this.columnConfigs = columnConfigs;
+ this.columnMappings = columnMappings;
+ }
+ }
+
+ /**
+ * Creates managers.
+ */
+ private static final class JdbcDatabaseManagerFactory implements ManagerFactory<JdbcDatabaseManager, FactoryData> {
+ @Override
+ public JdbcDatabaseManager createManager(final String name, final FactoryData data) {
+ final StringBuilder sb = new StringBuilder("INSERT INTO ").append(data.tableName).append(" (");
+ // so this gets a little more complicated now that there are two ways to configure column mappings, but
+ // both mappings follow the same exact pattern for the prepared statement
+ for (final ColumnMapping mapping : data.columnMappings) {
+ sb.append(mapping.getName()).append(',');
+ }
+ for (final ColumnConfig config : data.columnConfigs) {
+ sb.append(config.getColumnName()).append(',');
+ }
+ // at least one of those arrays is guaranteed to be non-empty
+ sb.setCharAt(sb.length() - 1, ')');
+ sb.append(" VALUES (");
+ final List<ColumnMapping> columnMappings = new ArrayList<>(data.columnMappings.length);
+ for (final ColumnMapping mapping : data.columnMappings) {
+ if (Strings.isNotEmpty(mapping.getLiteralValue())) {
+ sb.append(mapping.getLiteralValue());
+ } else {
+ sb.append('?');
+ columnMappings.add(mapping);
+ }
+ sb.append(',');
+ }
+ final List<ColumnConfig> columnConfigs = new ArrayList<>(data.columnConfigs.length);
+ for (final ColumnConfig config : data.columnConfigs) {
+ if (Strings.isNotEmpty(config.getLiteralValue())) {
+ sb.append(config.getLiteralValue());
+ } else {
+ sb.append('?');
+ columnConfigs.add(config);
+ }
+ sb.append(',');
+ }
+ // at least one of those arrays is guaranteed to be non-empty
+ sb.setCharAt(sb.length() - 1, ')');
+ final String sqlStatement = sb.toString();
+
+ return new JdbcDatabaseManager(name, data.getBufferSize(), data.connectionSource, sqlStatement,
+ columnConfigs, columnMappings);
+ }
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/26fc9e07/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/db/jpa/JpaDatabaseManager.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/db/jpa/JpaDatabaseManager.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/db/jpa/JpaDatabaseManager.java
index d5fc922..ddfa18e 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/db/jpa/JpaDatabaseManager.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/db/jpa/JpaDatabaseManager.java
@@ -1,193 +1,200 @@
-/*
- * 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.db.jpa;
-
-import java.lang.reflect.Constructor;
-
-import javax.persistence.EntityManager;
-import javax.persistence.EntityManagerFactory;
-import javax.persistence.EntityTransaction;
-import javax.persistence.Persistence;
-
-import org.apache.logging.log4j.core.LogEvent;
-import org.apache.logging.log4j.core.appender.AppenderLoggingException;
-import org.apache.logging.log4j.core.appender.ManagerFactory;
-import org.apache.logging.log4j.core.appender.db.AbstractDatabaseManager;
-
-/**
- * An {@link AbstractDatabaseManager} implementation for relational databases accessed via JPA.
- */
-public final class JpaDatabaseManager extends AbstractDatabaseManager {
- private static final JPADatabaseManagerFactory FACTORY = new JPADatabaseManagerFactory();
-
- private final String entityClassName;
- private final Constructor<? extends AbstractLogEventWrapperEntity> entityConstructor;
- private final String persistenceUnitName;
-
- private EntityManagerFactory entityManagerFactory;
-
- private EntityManager entityManager;
- private EntityTransaction transaction;
-
- private JpaDatabaseManager(final String name, final int bufferSize,
- final Class<? extends AbstractLogEventWrapperEntity> entityClass,
- final Constructor<? extends AbstractLogEventWrapperEntity> entityConstructor,
- final String persistenceUnitName) {
- super(name, bufferSize);
- this.entityClassName = entityClass.getName();
- this.entityConstructor = entityConstructor;
- this.persistenceUnitName = persistenceUnitName;
- }
-
- @Override
- protected void startupInternal() {
- this.entityManagerFactory = Persistence.createEntityManagerFactory(this.persistenceUnitName);
- }
-
- @Override
- protected boolean shutdownInternal() {
- boolean closed = true;
- if (this.entityManager != null || this.transaction != null) {
- closed &= this.commitAndClose();
- }
- if (this.entityManagerFactory != null && this.entityManagerFactory.isOpen()) {
- this.entityManagerFactory.close();
- }
- return closed;
- }
-
- @Override
- protected void connectAndStart() {
- try {
- this.entityManager = this.entityManagerFactory.createEntityManager();
- this.transaction = this.entityManager.getTransaction();
- this.transaction.begin();
- } catch (final Exception e) {
- throw new AppenderLoggingException(
- "Cannot write logging event or flush buffer; manager cannot create EntityManager or transaction.", e
- );
- }
- }
-
- @Override
- protected void writeInternal(final LogEvent event) {
- if (!this.isRunning() || this.entityManagerFactory == null || this.entityManager == null
- || this.transaction == null) {
- throw new AppenderLoggingException(
- "Cannot write logging event; JPA manager not connected to the database.");
- }
-
- AbstractLogEventWrapperEntity entity;
- try {
- entity = this.entityConstructor.newInstance(event);
- } catch (final Exception e) {
- throw new AppenderLoggingException("Failed to instantiate entity class [" + this.entityClassName + "].", e);
- }
-
- try {
- this.entityManager.persist(entity);
- } catch (final Exception e) {
- if (this.transaction != null && this.transaction.isActive()) {
- this.transaction.rollback();
- this.transaction = null;
- }
- throw new AppenderLoggingException("Failed to insert record for log event in JPA manager: " +
- e.getMessage(), e);
- }
- }
-
- @Override
- protected boolean commitAndClose() {
- boolean closed = true;
- try {
- if (this.transaction != null && this.transaction.isActive()) {
- this.transaction.commit();
- }
- } catch (final Exception e) {
- if (this.transaction != null && this.transaction.isActive()) {
- this.transaction.rollback();
- }
- } finally {
- this.transaction = null;
- try {
- if (this.entityManager != null && this.entityManager.isOpen()) {
- this.entityManager.close();
- }
- } catch (final Exception e) {
- logWarn("Failed to close entity manager while logging event or flushing buffer", e);
- closed = false;
- } finally {
- this.entityManager = null;
- }
- }
- return closed;
- }
-
- /**
- * Creates a JPA manager for use within the {@link JpaAppender}, or returns a suitable one if it already exists.
- *
- * @param name The name of the manager, which should include connection details, entity class name, etc.
- * @param bufferSize The size of the log event buffer.
- * @param entityClass The fully-qualified class name of the {@link AbstractLogEventWrapperEntity} concrete
- * implementation.
- * @param entityConstructor The one-arg {@link LogEvent} constructor for the concrete entity class.
- * @param persistenceUnitName The name of the JPA persistence unit that should be used for persisting log events.
- * @return a new or existing JPA manager as applicable.
- */
- public static JpaDatabaseManager getJPADatabaseManager(final String name, final int bufferSize,
- final Class<? extends AbstractLogEventWrapperEntity>
- entityClass,
- final Constructor<? extends AbstractLogEventWrapperEntity>
- entityConstructor,
- final String persistenceUnitName) {
-
- return AbstractDatabaseManager.getManager(
- name, new FactoryData(bufferSize, entityClass, entityConstructor, persistenceUnitName), FACTORY
- );
- }
-
- /**
- * Encapsulates data that {@link JPADatabaseManagerFactory} uses to create managers.
- */
- private static final class FactoryData extends AbstractDatabaseManager.AbstractFactoryData {
- private final Class<? extends AbstractLogEventWrapperEntity> entityClass;
- private final Constructor<? extends AbstractLogEventWrapperEntity> entityConstructor;
- private final String persistenceUnitName;
-
- protected FactoryData(final int bufferSize, final Class<? extends AbstractLogEventWrapperEntity> entityClass,
- final Constructor<? extends AbstractLogEventWrapperEntity> entityConstructor,
- final String persistenceUnitName) {
- super(bufferSize);
-
- this.entityClass = entityClass;
- this.entityConstructor = entityConstructor;
- this.persistenceUnitName = persistenceUnitName;
- }
- }
-
- /**
- * Creates managers.
- */
- private static final class JPADatabaseManagerFactory implements ManagerFactory<JpaDatabaseManager, FactoryData> {
- @Override
- public JpaDatabaseManager createManager(final String name, final FactoryData data) {
- return new JpaDatabaseManager(
- name, data.getBufferSize(), data.entityClass, data.entityConstructor, data.persistenceUnitName
- );
- }
- }
-}
+/*
+ * 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.db.jpa;
+
+import java.io.Serializable;
+import java.lang.reflect.Constructor;
+
+import javax.persistence.EntityManager;
+import javax.persistence.EntityManagerFactory;
+import javax.persistence.EntityTransaction;
+import javax.persistence.Persistence;
+
+import org.apache.logging.log4j.core.LogEvent;
+import org.apache.logging.log4j.core.appender.AppenderLoggingException;
+import org.apache.logging.log4j.core.appender.ManagerFactory;
+import org.apache.logging.log4j.core.appender.db.AbstractDatabaseManager;
+
+/**
+ * An {@link AbstractDatabaseManager} implementation for relational databases accessed via JPA.
+ */
+public final class JpaDatabaseManager extends AbstractDatabaseManager {
+ private static final JPADatabaseManagerFactory FACTORY = new JPADatabaseManagerFactory();
+
+ private final String entityClassName;
+ private final Constructor<? extends AbstractLogEventWrapperEntity> entityConstructor;
+ private final String persistenceUnitName;
+
+ private EntityManagerFactory entityManagerFactory;
+
+ private EntityManager entityManager;
+ private EntityTransaction transaction;
+
+ private JpaDatabaseManager(final String name, final int bufferSize,
+ final Class<? extends AbstractLogEventWrapperEntity> entityClass,
+ final Constructor<? extends AbstractLogEventWrapperEntity> entityConstructor,
+ final String persistenceUnitName) {
+ super(name, bufferSize);
+ this.entityClassName = entityClass.getName();
+ this.entityConstructor = entityConstructor;
+ this.persistenceUnitName = persistenceUnitName;
+ }
+
+ @Override
+ protected void startupInternal() {
+ this.entityManagerFactory = Persistence.createEntityManagerFactory(this.persistenceUnitName);
+ }
+
+ @Override
+ protected boolean shutdownInternal() {
+ boolean closed = true;
+ if (this.entityManager != null || this.transaction != null) {
+ closed &= this.commitAndClose();
+ }
+ if (this.entityManagerFactory != null && this.entityManagerFactory.isOpen()) {
+ this.entityManagerFactory.close();
+ }
+ return closed;
+ }
+
+ @Override
+ protected void connectAndStart() {
+ try {
+ this.entityManager = this.entityManagerFactory.createEntityManager();
+ this.transaction = this.entityManager.getTransaction();
+ this.transaction.begin();
+ } catch (final Exception e) {
+ throw new AppenderLoggingException(
+ "Cannot write logging event or flush buffer; manager cannot create EntityManager or transaction.", e
+ );
+ }
+ }
+
+ @Deprecated
+ @Override
+ protected void writeInternal(final LogEvent event) {
+ writeInternal(event, null);
+ }
+
+ @Override
+ protected void writeInternal(final LogEvent event, final Serializable serializable) {
+ if (!this.isRunning() || this.entityManagerFactory == null || this.entityManager == null
+ || this.transaction == null) {
+ throw new AppenderLoggingException(
+ "Cannot write logging event; JPA manager not connected to the database.");
+ }
+
+ AbstractLogEventWrapperEntity entity;
+ try {
+ entity = this.entityConstructor.newInstance(event);
+ } catch (final Exception e) {
+ throw new AppenderLoggingException("Failed to instantiate entity class [" + this.entityClassName + "].", e);
+ }
+
+ try {
+ this.entityManager.persist(entity);
+ } catch (final Exception e) {
+ if (this.transaction != null && this.transaction.isActive()) {
+ this.transaction.rollback();
+ this.transaction = null;
+ }
+ throw new AppenderLoggingException("Failed to insert record for log event in JPA manager: " +
+ e.getMessage(), e);
+ }
+ }
+
+ @Override
+ protected boolean commitAndClose() {
+ boolean closed = true;
+ try {
+ if (this.transaction != null && this.transaction.isActive()) {
+ this.transaction.commit();
+ }
+ } catch (final Exception e) {
+ if (this.transaction != null && this.transaction.isActive()) {
+ this.transaction.rollback();
+ }
+ } finally {
+ this.transaction = null;
+ try {
+ if (this.entityManager != null && this.entityManager.isOpen()) {
+ this.entityManager.close();
+ }
+ } catch (final Exception e) {
+ logWarn("Failed to close entity manager while logging event or flushing buffer", e);
+ closed = false;
+ } finally {
+ this.entityManager = null;
+ }
+ }
+ return closed;
+ }
+
+ /**
+ * Creates a JPA manager for use within the {@link JpaAppender}, or returns a suitable one if it already exists.
+ *
+ * @param name The name of the manager, which should include connection details, entity class name, etc.
+ * @param bufferSize The size of the log event buffer.
+ * @param entityClass The fully-qualified class name of the {@link AbstractLogEventWrapperEntity} concrete
+ * implementation.
+ * @param entityConstructor The one-arg {@link LogEvent} constructor for the concrete entity class.
+ * @param persistenceUnitName The name of the JPA persistence unit that should be used for persisting log events.
+ * @return a new or existing JPA manager as applicable.
+ */
+ public static JpaDatabaseManager getJPADatabaseManager(final String name, final int bufferSize,
+ final Class<? extends AbstractLogEventWrapperEntity>
+ entityClass,
+ final Constructor<? extends AbstractLogEventWrapperEntity>
+ entityConstructor,
+ final String persistenceUnitName) {
+
+ return AbstractDatabaseManager.getManager(
+ name, new FactoryData(bufferSize, entityClass, entityConstructor, persistenceUnitName), FACTORY
+ );
+ }
+
+ /**
+ * Encapsulates data that {@link JPADatabaseManagerFactory} uses to create managers.
+ */
+ private static final class FactoryData extends AbstractDatabaseManager.AbstractFactoryData {
+ private final Class<? extends AbstractLogEventWrapperEntity> entityClass;
+ private final Constructor<? extends AbstractLogEventWrapperEntity> entityConstructor;
+ private final String persistenceUnitName;
+
+ protected FactoryData(final int bufferSize, final Class<? extends AbstractLogEventWrapperEntity> entityClass,
+ final Constructor<? extends AbstractLogEventWrapperEntity> entityConstructor,
+ final String persistenceUnitName) {
+ super(bufferSize);
+
+ this.entityClass = entityClass;
+ this.entityConstructor = entityConstructor;
+ this.persistenceUnitName = persistenceUnitName;
+ }
+ }
+
+ /**
+ * Creates managers.
+ */
+ private static final class JPADatabaseManagerFactory implements ManagerFactory<JpaDatabaseManager, FactoryData> {
+ @Override
+ public JpaDatabaseManager createManager(final String name, final FactoryData data) {
+ return new JpaDatabaseManager(
+ name, data.getBufferSize(), data.entityClass, data.entityConstructor, data.persistenceUnitName
+ );
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/26fc9e07/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/mom/JmsAppender.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/mom/JmsAppender.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/mom/JmsAppender.java
index 57e8c75..1704018 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/mom/JmsAppender.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/mom/JmsAppender.java
@@ -266,7 +266,7 @@ public class JmsAppender extends AbstractAppender {
@Override
public void append(final LogEvent event) {
- this.manager.send(event, getLayout().toSerializable(event));
+ this.manager.send(event, toSerializable(event));
}
public JmsManager getManager() {