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 2020/05/23 22:58:11 UTC

[logging-log4j2] branch master updated: [LOG4J2-2848] Create module log4j-mongodb4 to use new major version 4 MongoDB driver.

This is an automated email from the ASF dual-hosted git repository.

ggregory pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/logging-log4j2.git


The following commit(s) were added to refs/heads/master by this push:
     new cf8aea0  [LOG4J2-2848] Create module log4j-mongodb4 to use new major version 4 MongoDB driver.
cf8aea0 is described below

commit cf8aea0cd18f5fcc01d901df01e6597f22e2f49b
Author: Gary Gregory <ga...@gmail.com>
AuthorDate: Sat May 23 18:58:04 2020 -0400

    [LOG4J2-2848] Create module log4j-mongodb4 to use new major version 4
    MongoDB driver.
    
    Also [LOG4J2-2851] Drop log4j-mongodb2 module.
---
 .../apache/logging/log4j/core/util/InitTest.java   |   6 +-
 log4j-mongodb2/revapi.json                         |  23 --
 .../logging/log4j/mongodb2/MongoDbConnection.java  | 103 -------
 .../logging/log4j/mongodb2/MongoDbProvider.java    | 309 ---------------------
 .../logging/log4j/mongodb2/MongoDbCappedTest.java  |  77 -----
 .../log4j/mongodb2/MongoDbMapMessageTest.java      |  81 ------
 .../apache/logging/log4j/mongodb2/MongoDbTest.java |  75 -----
 log4j-mongodb3/pom.xml                             |   2 +
 ...goDbConnection.java => MongoDb3Connection.java} |  12 +-
 ...mentObject.java => MongoDb3DocumentObject.java} |   4 +-
 .../{LevelCodec.java => MongoDb3LevelCodec.java}   |   4 +-
 ...{MongoDbProvider.java => MongoDb3Provider.java} |  18 +-
 ...ilureTest.java => MongoDb3AuthFailureTest.java} |  10 +-
 ...goDbCappedTest.java => MongoDb3CappedTest.java} |  10 +-
 ...essageTest.java => MongoDb3MapMessageTest.java} |  10 +-
 .../{MongoDbTest.java => MongoDb3Test.java}        |  10 +-
 ...stConstants.java => MongoDb3TestConstants.java} |   2 +-
 ...{MongoDbTestRule.java => MongoDb3TestRule.java} |   6 +-
 ...RuleTest.java => MongoDb3TestTestRuleTest.java} |  10 +-
 {log4j-mongodb2 => log4j-mongodb4}/pom.xml         |  25 +-
 .../logging/log4j/mongodb4/MongoDb4Connection.java |  53 ++--
 .../log4j/mongodb4/MongoDb4DocumentObject.java     |  46 ++-
 .../logging/log4j/mongodb4/MongoDb4LevelCodec.java |  12 +-
 .../logging/log4j/mongodb4/MongoDb4Provider.java   | 132 +++++++++
 .../logging/log4j/mongodb4}/package-info.java      |   5 +-
 .../src/site/markdown/index.md.vm                  |   2 +-
 .../src/site/site.xml                              |   2 +-
 .../log4j/mongodb4/MongoDb4AuthFailureTest.java    |  35 ++-
 .../logging/log4j/mongodb4/MongoDb4CappedTest.java |  20 +-
 .../log4j/mongodb4/MongoDb4MapMessageTest.java     |  20 +-
 .../logging/log4j/mongodb4/MongoDb4Test.java       |  20 +-
 .../log4j/mongodb4/MongoDb4TestConstants.java      |   4 +-
 .../logging/log4j/mongodb4/MongoDb4TestRule.java   | 100 +++----
 .../log4j/mongodb4/MongoDb4TestTestRuleTest.java   |  24 +-
 .../test/resources/log4j2-mongodb-auth-failure.xml |   4 +-
 .../src/test/resources/log4j2-mongodb-capped.xml   |   6 +-
 .../test/resources/log4j2-mongodb-map-message.xml  |   3 +-
 .../src/test/resources/log4j2-mongodb.xml          |   3 +-
 pom.xml                                            |  21 +-
 src/changes/changes.xml                            |   8 +
 src/site/asciidoc/javadoc.adoc                     |   6 +-
 src/site/asciidoc/manual/appenders.adoc            | 112 +++-----
 src/site/asciidoc/manual/messages.adoc             |   4 +-
 src/site/site.xml                                  |   4 +-
 44 files changed, 438 insertions(+), 1005 deletions(-)

diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/util/InitTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/util/InitTest.java
index 453fa19..5744886 100644
--- a/log4j-core/src/test/java/org/apache/logging/log4j/core/util/InitTest.java
+++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/util/InitTest.java
@@ -16,16 +16,18 @@
  */
 package org.apache.logging.log4j.core.util;
 
+import static org.junit.Assert.assertTrue;
+
 import org.apache.logging.log4j.LogManager;
 import org.apache.logging.log4j.Logger;
 import org.apache.logging.log4j.util.Timer;
+import org.junit.Ignore;
 import org.junit.Test;
 
-import static org.junit.Assert.assertTrue;
-
 /**
  * Test initialization.
  */
+@Ignore
 public class InitTest {
 
     @Test
diff --git a/log4j-mongodb2/revapi.json b/log4j-mongodb2/revapi.json
deleted file mode 100644
index bd8fb67..0000000
--- a/log4j-mongodb2/revapi.json
+++ /dev/null
@@ -1,23 +0,0 @@
-[
-  {
-    "extension": "revapi.java",
-    "configuration": {
-      "filter": {
-        "classes": {
-          "exclude": [
-          ]
-        }
-      }
-    }
-  },
-  {
-    "extension": "revapi.ignore",
-    "configuration": [
-      {
-        "code": "java.method.removed",
-        "old": "method org.apache.logging.log4j.mongodb2.MongoDbProvider org.apache.logging.log4j.mongodb2.MongoDbProvider::createNoSqlProvider(java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String)",
-        "justification": "LOG4J2-2493 - Remove deprecated code"
-      }
-    ]
-  }
-]
\ No newline at end of file
diff --git a/log4j-mongodb2/src/main/java/org/apache/logging/log4j/mongodb2/MongoDbConnection.java b/log4j-mongodb2/src/main/java/org/apache/logging/log4j/mongodb2/MongoDbConnection.java
deleted file mode 100644
index ec3b7dd..0000000
--- a/log4j-mongodb2/src/main/java/org/apache/logging/log4j/mongodb2/MongoDbConnection.java
+++ /dev/null
@@ -1,103 +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.mongodb2;
-
-import org.apache.logging.log4j.Level;
-import org.apache.logging.log4j.Logger;
-import org.apache.logging.log4j.core.appender.AppenderLoggingException;
-import org.apache.logging.log4j.core.appender.nosql.AbstractNoSqlConnection;
-import org.apache.logging.log4j.core.appender.nosql.NoSqlConnection;
-import org.apache.logging.log4j.core.appender.nosql.NoSqlObject;
-import org.apache.logging.log4j.status.StatusLogger;
-import org.bson.BSON;
-import org.bson.Transformer;
-
-import com.mongodb.BasicDBObject;
-import com.mongodb.DB;
-import com.mongodb.DBCollection;
-import com.mongodb.Mongo;
-import com.mongodb.MongoException;
-import com.mongodb.WriteConcern;
-
-/**
- * The MongoDB implementation of {@link NoSqlConnection}.
- */
-public final class MongoDbConnection extends AbstractNoSqlConnection<BasicDBObject, MongoDbObject> {
-
-    private static final Logger LOGGER = StatusLogger.getLogger();
-
-    static {
-        BSON.addEncodingHook(Level.class, new Transformer() {
-            @Override
-            public Object transform(final Object o) {
-                if (o instanceof Level) {
-                    return ((Level) o).name();
-                }
-                return o;
-            }
-        });
-    }
-
-    private final DBCollection collection;
-    private final WriteConcern writeConcern;
-
-    public MongoDbConnection(final DB database, final WriteConcern writeConcern, final String collectionName,
-            final Boolean isCapped, final Integer collectionSize) {
-        if (database.collectionExists(collectionName)) {
-            LOGGER.debug("Gettting collection {}", collectionName);
-            collection = database.getCollection(collectionName);
-        } else {
-            final BasicDBObject options = new BasicDBObject();
-            options.put("capped", isCapped);
-            options.put("size", collectionSize);
-            LOGGER.debug("Creating collection {} (capped = {}, size = {})", collectionName, isCapped, collectionSize);
-            this.collection = database.createCollection(collectionName, options);
-        }
-        this.writeConcern = writeConcern;
-    }
-
-    @Override
-    public void closeImpl() {
-        // LOG4J2-1196
-        final Mongo mongo = this.collection.getDB().getMongo();
-        LOGGER.debug("Closing {} client {}", mongo.getClass().getSimpleName(), mongo);
-        mongo.close();
-    }
-
-    @Override
-    public MongoDbObject[] createList(final int length) {
-        return new MongoDbObject[length];
-    }
-
-    @Override
-    public MongoDbObject createObject() {
-        return new MongoDbObject();
-    }
-
-    @Override
-    public void insertObject(final NoSqlObject<BasicDBObject> object) {
-        try {
-            final BasicDBObject unwrapped = object.unwrap();
-            LOGGER.debug("Inserting object {}", unwrapped);
-            this.collection.insert(unwrapped, this.writeConcern);
-        } catch (final MongoException e) {
-            throw new AppenderLoggingException("Failed to write log event to MongoDB due to error: " + e.getMessage(),
-                    e);
-        }
-    }
-
-}
diff --git a/log4j-mongodb2/src/main/java/org/apache/logging/log4j/mongodb2/MongoDbProvider.java b/log4j-mongodb2/src/main/java/org/apache/logging/log4j/mongodb2/MongoDbProvider.java
deleted file mode 100644
index 1022a50..0000000
--- a/log4j-mongodb2/src/main/java/org/apache/logging/log4j/mongodb2/MongoDbProvider.java
+++ /dev/null
@@ -1,309 +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.mongodb2;
-
-import java.lang.reflect.Field;
-import java.lang.reflect.Method;
-import java.util.ArrayList;
-import java.util.List;
-
-import org.apache.logging.log4j.Logger;
-import org.apache.logging.log4j.core.Core;
-import org.apache.logging.log4j.core.appender.nosql.NoSqlProvider;
-import org.apache.logging.log4j.core.filter.AbstractFilterable;
-import org.apache.logging.log4j.plugins.Plugin;
-import org.apache.logging.log4j.plugins.PluginBuilderAttribute;
-import org.apache.logging.log4j.plugins.PluginFactory;
-import org.apache.logging.log4j.plugins.convert.TypeConverters;
-import org.apache.logging.log4j.plugins.validation.constraints.Required;
-import org.apache.logging.log4j.plugins.validation.constraints.ValidHost;
-import org.apache.logging.log4j.plugins.validation.constraints.ValidPort;
-import org.apache.logging.log4j.status.StatusLogger;
-import org.apache.logging.log4j.util.LoaderUtil;
-import org.apache.logging.log4j.util.NameUtil;
-import org.apache.logging.log4j.util.Strings;
-
-import com.mongodb.DB;
-import com.mongodb.MongoClient;
-import com.mongodb.MongoCredential;
-import com.mongodb.ServerAddress;
-import com.mongodb.WriteConcern;
-
-/**
- * The MongoDB implementation of {@link NoSqlProvider} using the MongoDB driver version 2 API.
- */
-@Plugin(name = "MongoDb2", category = Core.CATEGORY_NAME, printObject = true)
-public final class MongoDbProvider implements NoSqlProvider<MongoDbConnection> {
-
-    public static class Builder<B extends Builder<B>> extends AbstractFilterable.Builder<B>
-			implements org.apache.logging.log4j.plugins.util.Builder<MongoDbProvider> {
-
-		private static WriteConcern toWriteConcern(final String writeConcernConstant,
-	            final String writeConcernConstantClassName) {
-	        WriteConcern writeConcern;
-	        if (Strings.isNotEmpty(writeConcernConstant)) {
-	            if (Strings.isNotEmpty(writeConcernConstantClassName)) {
-	                try {
-	                    final Class<?> writeConcernConstantClass = LoaderUtil.loadClass(writeConcernConstantClassName);
-	                    final Field field = writeConcernConstantClass.getField(writeConcernConstant);
-	                    writeConcern = (WriteConcern) field.get(null);
-	                } catch (final Exception e) {
-	                    LOGGER.error("Write concern constant [{}.{}] not found, using default.",
-	                            writeConcernConstantClassName, writeConcernConstant);
-	                    writeConcern = DEFAULT_WRITE_CONCERN;
-	                }
-	            } else {
-	                writeConcern = WriteConcern.valueOf(writeConcernConstant);
-	                if (writeConcern == null) {
-	                    LOGGER.warn("Write concern constant [{}] not found, using default.", writeConcernConstant);
-	                    writeConcern = DEFAULT_WRITE_CONCERN;
-	                }
-	            }
-	        } else {
-	            writeConcern = DEFAULT_WRITE_CONCERN;
-	        }
-	        return writeConcern;
-	    }
-
-		@PluginBuilderAttribute
-		@ValidHost
-		private String server = "localhost";
-
-		@PluginBuilderAttribute
-		@ValidPort
-		private String port = "" + DEFAULT_PORT;
-
-		@PluginBuilderAttribute
-		@Required(message = "No database name provided")
-		private String databaseName;
-
-		@PluginBuilderAttribute
-		@Required(message = "No collection name provided")
-		private String collectionName;
-
-		@PluginBuilderAttribute
-		private String userName;
-
-		@PluginBuilderAttribute(sensitive = true)
-		private String password;
-
-		@PluginBuilderAttribute("capped")
-		private boolean isCapped = false;
-
-		@PluginBuilderAttribute
-		private int collectionSize = DEFAULT_COLLECTION_SIZE;
-
-		@PluginBuilderAttribute
-		private String factoryClassName;
-
-		@PluginBuilderAttribute
-		private String factoryMethodName;
-
-		@PluginBuilderAttribute
-		private String writeConcernConstantClassName;
-
-		@PluginBuilderAttribute
-		private String writeConcernConstant;
-
-		@Override
-		public MongoDbProvider build() {
-	        DB database;
-	        String description;
-	        if (Strings.isNotEmpty(factoryClassName) && Strings.isNotEmpty(factoryMethodName)) {
-	            try {
-	                final Class<?> factoryClass = LoaderUtil.loadClass(factoryClassName);
-	                final Method method = factoryClass.getMethod(factoryMethodName);
-	                final Object object = method.invoke(null);
-
-	                if (object instanceof DB) {
-	                    database = (DB) object;
-	                } else if (object instanceof MongoClient) {
-	                    if (Strings.isNotEmpty(databaseName)) {
-	                        database = ((MongoClient) object).getDB(databaseName);
-	                    } else {
-	                        LOGGER.error("The factory method [{}.{}()] returned a MongoClient so the database name is "
-	                                + "required.", factoryClassName, factoryMethodName);
-	                        return null;
-	                    }
-	                } else if (object == null) {
-	                    LOGGER.error("The factory method [{}.{}()] returned null.", factoryClassName, factoryMethodName);
-	                    return null;
-	                } else {
-	                    LOGGER.error("The factory method [{}.{}()] returned an unsupported type [{}].", factoryClassName,
-	                            factoryMethodName, object.getClass().getName());
-	                    return null;
-	                }
-
-	                description = "database=" + database.getName();
-	                final List<ServerAddress> addresses = database.getMongo().getAllAddress();
-	                if (addresses.size() == 1) {
-	                    description += ", server=" + addresses.get(0).getHost() + ", port=" + addresses.get(0).getPort();
-	                } else {
-	                    description += ", servers=[";
-	                    for (final ServerAddress address : addresses) {
-	                        description += " { " + address.getHost() + ", " + address.getPort() + " } ";
-	                    }
-	                    description += "]";
-	                }
-	            } catch (final ClassNotFoundException e) {
-	                LOGGER.error("The factory class [{}] could not be loaded.", factoryClassName, e);
-	                return null;
-	            } catch (final NoSuchMethodException e) {
-	                LOGGER.error("The factory class [{}] does not have a no-arg method named [{}].", factoryClassName,
-	                        factoryMethodName, e);
-	                return null;
-	            } catch (final Exception e) {
-	                LOGGER.error("The factory method [{}.{}()] could not be invoked.", factoryClassName, factoryMethodName,
-	                        e);
-	                return null;
-	            }
-	        } else if (Strings.isNotEmpty(databaseName)) {
-	            final List<MongoCredential> credentials = new ArrayList<>();
-	            description = "database=" + databaseName;
-	            if (Strings.isNotEmpty(userName) && Strings.isNotEmpty(password)) {
-	                description += ", username=" + userName + ", passwordHash="
-	                        + NameUtil.md5(password + MongoDbProvider.class.getName());
-	                credentials.add(MongoCredential.createCredential(userName, databaseName, password.toCharArray()));
-	            }
-	            try {
-	                final int portInt = TypeConverters.convert(port, int.class, DEFAULT_PORT);
-	                description += ", server=" + server + ", port=" + portInt;
-	                database = new MongoClient(new ServerAddress(server, portInt), credentials).getDB(databaseName);
-	            } catch (final Exception e) {
-	                LOGGER.error(
-	                        "Failed to obtain a database instance from the MongoClient at server [{}] and " + "port [{}].",
-	                        server, port);
-	                return null;
-	            }
-	        } else {
-	            LOGGER.error("No factory method was provided so the database name is required.");
-	            return null;
-	        }
-
-	        try {
-	            database.getCollectionNames(); // Check if the database actually requires authentication
-	        } catch (final Exception e) {
-	            LOGGER.error(
-	                    "The database is not up, or you are not authenticated, try supplying a username and password to the MongoDB provider.",
-	                    e);
-	            return null;
-	        }
-
-	        final WriteConcern writeConcern = toWriteConcern(writeConcernConstant, writeConcernConstantClassName);
-
-	        return new MongoDbProvider(database, writeConcern, collectionName, isCapped, collectionSize, description);
-		}
-
-		public B setCapped(final boolean isCapped) {
-			this.isCapped = isCapped;
-			return asBuilder();
-		}
-
-		public B setCollectionName(final String collectionName) {
-			this.collectionName = collectionName;
-			return asBuilder();
-		}
-
-		public B setCollectionSize(final int collectionSize) {
-			this.collectionSize = collectionSize;
-			return asBuilder();
-		}
-
-		public B setDatabaseName(final String databaseName) {
-			this.databaseName = databaseName;
-			return asBuilder();
-		}
-
-		public B setFactoryClassName(final String factoryClassName) {
-			this.factoryClassName = factoryClassName;
-			return asBuilder();
-		}
-
-		public B setFactoryMethodName(final String factoryMethodName) {
-			this.factoryMethodName = factoryMethodName;
-			return asBuilder();
-		}
-
-		public B setPassword(final String password) {
-			this.password = password;
-			return asBuilder();
-		}
-
-		public B setPort(final String port) {
-			this.port = port;
-			return asBuilder();
-		}
-
-		public B setServer(final String server) {
-			this.server = server;
-			return asBuilder();
-		}
-
-		public B setUserName(final String userName) {
-			this.userName = userName;
-			return asBuilder();
-		}
-
-		public B setWriteConcernConstant(final String writeConcernConstant) {
-			this.writeConcernConstant = writeConcernConstant;
-			return asBuilder();
-		}
-
-	    public B setWriteConcernConstantClassName(final String writeConcernConstantClassName) {
-			this.writeConcernConstantClassName = writeConcernConstantClassName;
-			return asBuilder();
-		}
-    }
-    private static final WriteConcern DEFAULT_WRITE_CONCERN = WriteConcern.ACKNOWLEDGED;
-    private static final Logger LOGGER = StatusLogger.getLogger();
-    private static final int DEFAULT_PORT = 27017;
-
-    private static final int DEFAULT_COLLECTION_SIZE = 536870912;
-    @PluginFactory
-	public static <B extends Builder<B>> B newBuilder() {
-		return new Builder<B>().asBuilder();
-	}
-    private final String collectionName;
-    private final DB database;
-    private final String description;
-
-    private final WriteConcern writeConcern;
-
-    private final boolean isCapped;
-
-    private final Integer collectionSize;
-
-    private MongoDbProvider(final DB database, final WriteConcern writeConcern, final String collectionName,
-            final boolean isCapped, final Integer collectionSize, final String description) {
-        this.database = database;
-        this.writeConcern = writeConcern;
-        this.collectionName = collectionName;
-        this.isCapped = isCapped;
-        this.collectionSize = collectionSize;
-        this.description = "mongoDb{ " + description + " }";
-    }
-
-	@Override
-    public MongoDbConnection getConnection() {
-        return new MongoDbConnection(this.database, this.writeConcern, this.collectionName, this.isCapped, this.collectionSize);
-    }
-
-	@Override
-    public String toString() {
-        return this.description;
-    }
-}
diff --git a/log4j-mongodb2/src/test/java/org/apache/logging/log4j/mongodb2/MongoDbCappedTest.java b/log4j-mongodb2/src/test/java/org/apache/logging/log4j/mongodb2/MongoDbCappedTest.java
deleted file mode 100644
index aa171c8..0000000
--- a/log4j-mongodb2/src/test/java/org/apache/logging/log4j/mongodb2/MongoDbCappedTest.java
+++ /dev/null
@@ -1,77 +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.mongodb2;
-
-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.mongodb2.MongoDbTestRule.LoggingTarget;
-import org.apache.logging.log4j.test.AvailablePortSystemPropertyTestRule;
-import org.apache.logging.log4j.test.RuleChainFactory;
-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.DB;
-import com.mongodb.DBCollection;
-import com.mongodb.DBCursor;
-import com.mongodb.DBObject;
-import com.mongodb.MongoClient;
-
-/**
- * This class name does NOT end in "Test" in order to only be picked up by {@link Java8Test}.
- */
-@Category(Appenders.MongoDb.class)
-public class MongoDbCappedTest {
-
-    private static LoggerContextRule loggerContextTestRule = new LoggerContextRule("log4j2-mongodb-capped.xml");
-
-    private static final AvailablePortSystemPropertyTestRule mongoDbPortTestRule = AvailablePortSystemPropertyTestRule
-            .create(TestConstants.SYS_PROP_NAME_PORT);
-
-    private static final MongoDbTestRule mongoDbTestRule = new MongoDbTestRule(mongoDbPortTestRule.getName(), LoggingTarget.NULL);
-
-    @ClassRule
-    public static RuleChain ruleChain = RuleChainFactory.create(mongoDbPortTestRule, mongoDbTestRule,
-            loggerContextTestRule);
-
-    @Test
-    public void test() {
-        final Logger logger = LogManager.getLogger();
-        logger.info("Hello log");
-        final MongoClient mongoClient = mongoDbTestRule.getMongoClient();
-        try {
-            final DB database = mongoClient.getDB("test");
-            Assert.assertNotNull(database);
-            final DBCollection collection = database.getCollection("applog");
-            Assert.assertNotNull(collection);
-            try (DBCursor cursor = collection.find()) {
-                Assert.assertTrue(cursor.hasNext());
-            }
-            try (DBCursor cursor = collection.find()) {
-                final DBObject first = cursor.next();
-                Assert.assertNotNull(first);
-                Assert.assertEquals(first.toMap().toString(), "Hello log", first.get("message"));
-            }
-        } finally {
-            mongoClient.close();
-        }
-    }
-}
diff --git a/log4j-mongodb2/src/test/java/org/apache/logging/log4j/mongodb2/MongoDbMapMessageTest.java b/log4j-mongodb2/src/test/java/org/apache/logging/log4j/mongodb2/MongoDbMapMessageTest.java
deleted file mode 100644
index cec53d7..0000000
--- a/log4j-mongodb2/src/test/java/org/apache/logging/log4j/mongodb2/MongoDbMapMessageTest.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.mongodb2;
-
-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.mongodb2.MongoDbTestRule.LoggingTarget;
-import org.apache.logging.log4j.test.AvailablePortSystemPropertyTestRule;
-import org.apache.logging.log4j.test.RuleChainFactory;
-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.DB;
-import com.mongodb.DBCollection;
-import com.mongodb.DBCursor;
-import com.mongodb.DBObject;
-import com.mongodb.MongoClient;
-
-/**
- * This class name does NOT end in "Test" in order to only be picked up by {@link Java8Test}.
- */
-@Category(Appenders.MongoDb.class)
-public class MongoDbMapMessageTest {
-
-    private static LoggerContextRule loggerContextTestRule = new LoggerContextRule("log4j2-mongodb-map-message.xml");
-
-    private static final AvailablePortSystemPropertyTestRule mongoDbPortTestRule = AvailablePortSystemPropertyTestRule
-            .create(TestConstants.SYS_PROP_NAME_PORT);
-
-    private static final MongoDbTestRule mongoDbTestRule = new MongoDbTestRule(mongoDbPortTestRule.getName(), LoggingTarget.NULL);
-
-    @ClassRule
-    public static RuleChain ruleChain = RuleChainFactory.create(mongoDbPortTestRule, mongoDbTestRule,
-            loggerContextTestRule);
-
-    @Test
-    public void test() {
-        final Logger logger = LogManager.getLogger();
-        final MapMessage<?, Object> mapMessage = new MapMessage<>();
-        mapMessage.with("SomeName", "SomeValue");
-        mapMessage.with("SomeInt", 1);
-        logger.info(mapMessage);
-        //
-        final MongoClient mongoClient = mongoDbTestRule.getMongoClient();
-        try {
-            final DB database = mongoClient.getDB("test");
-            Assert.assertNotNull(database);
-            final DBCollection collection = database.getCollection("applog");
-            Assert.assertNotNull(collection);
-            try (DBCursor cursor = collection.find()) {
-                final DBObject first = cursor.next();
-                Assert.assertNotNull(first);
-                final String firstMapString = first.toMap().toString();
-                Assert.assertEquals(firstMapString, "SomeValue", first.get("SomeName"));
-                Assert.assertEquals(firstMapString, Integer.valueOf(1), first.get("SomeInt"));
-            }
-        } finally {
-            mongoClient.close();
-        }
-    }
-}
diff --git a/log4j-mongodb2/src/test/java/org/apache/logging/log4j/mongodb2/MongoDbTest.java b/log4j-mongodb2/src/test/java/org/apache/logging/log4j/mongodb2/MongoDbTest.java
deleted file mode 100644
index 08c92d2..0000000
--- a/log4j-mongodb2/src/test/java/org/apache/logging/log4j/mongodb2/MongoDbTest.java
+++ /dev/null
@@ -1,75 +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.mongodb2;
-
-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.mongodb2.MongoDbTestRule.LoggingTarget;
-import org.apache.logging.log4j.test.AvailablePortSystemPropertyTestRule;
-import org.apache.logging.log4j.test.RuleChainFactory;
-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.DB;
-import com.mongodb.DBCollection;
-import com.mongodb.DBCursor;
-import com.mongodb.DBObject;
-import com.mongodb.MongoClient;
-
-/**
- * This class name does NOT end in "Test" in order to only be picked up by {@link Java8Test}.
- */
-@Category(Appenders.MongoDb.class)
-public class MongoDbTest {
-
-    private static LoggerContextRule loggerContextTestRule = new LoggerContextRule("log4j2-mongodb.xml");
-
-    private static final AvailablePortSystemPropertyTestRule mongoDbPortTestRule = AvailablePortSystemPropertyTestRule
-            .create(TestConstants.SYS_PROP_NAME_PORT);
-
-    private static final MongoDbTestRule mongoDbTestRule = new MongoDbTestRule(mongoDbPortTestRule.getName(), LoggingTarget.NULL);
-
-    @ClassRule
-    public static RuleChain ruleChain = RuleChainFactory.create(mongoDbPortTestRule, mongoDbTestRule,
-            loggerContextTestRule);
-
-    @Test
-    public void test() {
-        final Logger logger = LogManager.getLogger();
-        logger.info("Hello log");
-        final MongoClient mongoClient = mongoDbTestRule.getMongoClient();
-        try {
-            final DB database = mongoClient.getDB("test");
-            Assert.assertNotNull(database);
-            final DBCollection collection = database.getCollection("applog");
-            Assert.assertNotNull(collection);
-            try (DBCursor cursor = collection.find()) {
-                final DBObject first = cursor.next();
-                Assert.assertNotNull(first);
-                Assert.assertEquals(first.toMap().toString(), "Hello log", first.get("message"));
-                Assert.assertEquals(first.toMap().toString(), "INFO", first.get("level"));
-            }
-        } finally {
-            mongoClient.close();
-        }
-    }
-}
diff --git a/log4j-mongodb3/pom.xml b/log4j-mongodb3/pom.xml
index 03e6f97..e634c50 100644
--- a/log4j-mongodb3/pom.xml
+++ b/log4j-mongodb3/pom.xml
@@ -44,10 +44,12 @@
     <dependency>
       <groupId>org.mongodb</groupId>
       <artifactId>mongodb-driver</artifactId>
+      <version>${mongodb3.version}</version>
     </dependency>
     <dependency>
       <groupId>org.mongodb</groupId>
       <artifactId>bson</artifactId>
+      <version>${mongodb3.version}</version>
     </dependency>
     <!-- Test Dependencies -->
     <dependency>
diff --git a/log4j-mongodb3/src/main/java/org/apache/logging/log4j/mongodb3/MongoDbConnection.java b/log4j-mongodb3/src/main/java/org/apache/logging/log4j/mongodb3/MongoDb3Connection.java
similarity index 89%
copy from log4j-mongodb3/src/main/java/org/apache/logging/log4j/mongodb3/MongoDbConnection.java
copy to log4j-mongodb3/src/main/java/org/apache/logging/log4j/mongodb3/MongoDb3Connection.java
index 34d0613..512d3ff 100644
--- a/log4j-mongodb3/src/main/java/org/apache/logging/log4j/mongodb3/MongoDbConnection.java
+++ b/log4j-mongodb3/src/main/java/org/apache/logging/log4j/mongodb3/MongoDb3Connection.java
@@ -33,7 +33,7 @@ import com.mongodb.client.model.CreateCollectionOptions;
 /**
  * The MongoDB implementation of {@link NoSqlConnection}.
  */
-public final class MongoDbConnection extends AbstractNoSqlConnection<Document, MongoDbDocumentObject> {
+public final class MongoDb3Connection extends AbstractNoSqlConnection<Document, MongoDb3DocumentObject> {
 
     private static final Logger LOGGER = StatusLogger.getLogger();
 
@@ -61,7 +61,7 @@ public final class MongoDbConnection extends AbstractNoSqlConnection<Document, M
     private final MongoCollection<Document> collection;
     private final MongoClient mongoClient;
 
-    public MongoDbConnection(final MongoClient mongoClient, final MongoDatabase mongoDatabase,
+    public MongoDb3Connection(final MongoClient mongoClient, final MongoDatabase mongoDatabase,
             final String collectionName, final boolean isCapped, final Integer sizeInBytes) {
         this.mongoClient = mongoClient;
         this.collection = getOrCreateMongoCollection(mongoDatabase, collectionName, isCapped, sizeInBytes);
@@ -74,13 +74,13 @@ public final class MongoDbConnection extends AbstractNoSqlConnection<Document, M
     }
 
     @Override
-    public MongoDbDocumentObject[] createList(final int length) {
-        return new MongoDbDocumentObject[length];
+    public MongoDb3DocumentObject[] createList(final int length) {
+        return new MongoDb3DocumentObject[length];
     }
 
     @Override
-    public MongoDbDocumentObject createObject() {
-        return new MongoDbDocumentObject();
+    public MongoDb3DocumentObject createObject() {
+        return new MongoDb3DocumentObject();
     }
 
     @Override
diff --git a/log4j-mongodb3/src/main/java/org/apache/logging/log4j/mongodb3/MongoDbDocumentObject.java b/log4j-mongodb3/src/main/java/org/apache/logging/log4j/mongodb3/MongoDb3DocumentObject.java
similarity index 94%
rename from log4j-mongodb3/src/main/java/org/apache/logging/log4j/mongodb3/MongoDbDocumentObject.java
rename to log4j-mongodb3/src/main/java/org/apache/logging/log4j/mongodb3/MongoDb3DocumentObject.java
index 49bdc88..3132d26 100644
--- a/log4j-mongodb3/src/main/java/org/apache/logging/log4j/mongodb3/MongoDbDocumentObject.java
+++ b/log4j-mongodb3/src/main/java/org/apache/logging/log4j/mongodb3/MongoDb3DocumentObject.java
@@ -24,10 +24,10 @@ import org.bson.Document;
 /**
  * The MongoDB implementation of {@link NoSqlObject} typed to a BSON {@link Document}.
  */
-public final class MongoDbDocumentObject implements NoSqlObject<Document> {
+public final class MongoDb3DocumentObject implements NoSqlObject<Document> {
     private final Document document;
 
-    public MongoDbDocumentObject() {
+    public MongoDb3DocumentObject() {
         this.document = new Document();
     }
 
diff --git a/log4j-mongodb3/src/main/java/org/apache/logging/log4j/mongodb3/LevelCodec.java b/log4j-mongodb3/src/main/java/org/apache/logging/log4j/mongodb3/MongoDb3LevelCodec.java
similarity index 92%
copy from log4j-mongodb3/src/main/java/org/apache/logging/log4j/mongodb3/LevelCodec.java
copy to log4j-mongodb3/src/main/java/org/apache/logging/log4j/mongodb3/MongoDb3LevelCodec.java
index f900863..0ecefcf 100644
--- a/log4j-mongodb3/src/main/java/org/apache/logging/log4j/mongodb3/LevelCodec.java
+++ b/log4j-mongodb3/src/main/java/org/apache/logging/log4j/mongodb3/MongoDb3LevelCodec.java
@@ -27,14 +27,14 @@ import org.bson.codecs.EncoderContext;
 /**
  * A BSON Codec for Log4j {@link Level}s.
  */
-public class LevelCodec implements Codec<Level> {
+public class MongoDb3LevelCodec implements Codec<Level> {
 
     /**
      * The singleton instance.
      *
      * @since 2.14.0
      */
-    public static final LevelCodec INSTANCE = new LevelCodec();
+    public static final MongoDb3LevelCodec INSTANCE = new MongoDb3LevelCodec();
     
     @Override
     public Level decode(final BsonReader reader, final DecoderContext decoderContext) {
diff --git a/log4j-mongodb3/src/main/java/org/apache/logging/log4j/mongodb3/MongoDbProvider.java b/log4j-mongodb3/src/main/java/org/apache/logging/log4j/mongodb3/MongoDb3Provider.java
similarity index 95%
rename from log4j-mongodb3/src/main/java/org/apache/logging/log4j/mongodb3/MongoDbProvider.java
rename to log4j-mongodb3/src/main/java/org/apache/logging/log4j/mongodb3/MongoDb3Provider.java
index c329d13..d38cab8 100644
--- a/log4j-mongodb3/src/main/java/org/apache/logging/log4j/mongodb3/MongoDbProvider.java
+++ b/log4j-mongodb3/src/main/java/org/apache/logging/log4j/mongodb3/MongoDb3Provider.java
@@ -48,14 +48,14 @@ import com.mongodb.client.MongoDatabase;
  * The MongoDB implementation of {@link NoSqlProvider} using the MongoDB driver version 3 API.
  */
 @Plugin(name = "MongoDb3", category = Core.CATEGORY_NAME, printObject = true)
-public final class MongoDbProvider implements NoSqlProvider<MongoDbConnection> {
+public final class MongoDb3Provider implements NoSqlProvider<MongoDb3Connection> {
 
     public static class Builder<B extends Builder<B>> extends AbstractFilterable.Builder<B>
-            implements org.apache.logging.log4j.plugins.util.Builder<MongoDbProvider> {
+            implements org.apache.logging.log4j.plugins.util.Builder<MongoDb3Provider> {
 
         // @formatter:off
         private static final CodecRegistry CODEC_REGISTRIES = CodecRegistries.fromRegistries(
-                        CodecRegistries.fromCodecs(LevelCodec.INSTANCE),
+                        CodecRegistries.fromCodecs(MongoDb3LevelCodec.INSTANCE),
                         MongoClient.getDefaultCodecRegistry());
         // @formatter:on
 
@@ -128,7 +128,7 @@ public final class MongoDbProvider implements NoSqlProvider<MongoDbConnection> {
 
         @SuppressWarnings("resource")
         @Override
-        public MongoDbProvider build() {
+        public MongoDb3Provider build() {
             MongoDatabase database;
             String description;
             MongoClient mongoClient = null;
@@ -178,7 +178,7 @@ public final class MongoDbProvider implements NoSqlProvider<MongoDbConnection> {
                 description = "database=" + databaseName;
                 if (Strings.isNotEmpty(userName) && Strings.isNotEmpty(password)) {
                     description += ", username=" + userName + ", passwordHash="
-                            + NameUtil.md5(password + MongoDbProvider.class.getName());
+                            + NameUtil.md5(password + MongoDb3Provider.class.getName());
                     mongoCredential = MongoCredential.createCredential(userName, databaseName, password.toCharArray());
                 }
                 try {
@@ -220,7 +220,7 @@ public final class MongoDbProvider implements NoSqlProvider<MongoDbConnection> {
                 return null;
             }
 
-            return new MongoDbProvider(mongoClient, database, collectionName, capped, collectionSize, description);
+            return new MongoDb3Provider(mongoClient, database, collectionName, capped, collectionSize, description);
         }
 
         private void close(final MongoClient mongoClient) {
@@ -308,7 +308,7 @@ public final class MongoDbProvider implements NoSqlProvider<MongoDbConnection> {
     private final MongoClient mongoClient;
     private final MongoDatabase mongoDatabase;
 
-    private MongoDbProvider(final MongoClient mongoClient, final MongoDatabase mongoDatabase,
+    private MongoDb3Provider(final MongoClient mongoClient, final MongoDatabase mongoDatabase,
             final String collectionName, final boolean isCapped, final Integer collectionSize,
             final String description) {
         this.mongoClient = mongoClient;
@@ -320,8 +320,8 @@ public final class MongoDbProvider implements NoSqlProvider<MongoDbConnection> {
     }
 
     @Override
-    public MongoDbConnection getConnection() {
-        return new MongoDbConnection(mongoClient, mongoDatabase, collectionName, isCapped, collectionSize);
+    public MongoDb3Connection getConnection() {
+        return new MongoDb3Connection(mongoClient, mongoDatabase, collectionName, isCapped, collectionSize);
     }
 
     @Override
diff --git a/log4j-mongodb3/src/test/java/org/apache/logging/log4j/mongodb3/MongoDbAuthFailureTest.java b/log4j-mongodb3/src/test/java/org/apache/logging/log4j/mongodb3/MongoDb3AuthFailureTest.java
similarity index 88%
rename from log4j-mongodb3/src/test/java/org/apache/logging/log4j/mongodb3/MongoDbAuthFailureTest.java
rename to log4j-mongodb3/src/test/java/org/apache/logging/log4j/mongodb3/MongoDb3AuthFailureTest.java
index 19a45c8..540be57 100644
--- a/log4j-mongodb3/src/test/java/org/apache/logging/log4j/mongodb3/MongoDbAuthFailureTest.java
+++ b/log4j-mongodb3/src/test/java/org/apache/logging/log4j/mongodb3/MongoDb3AuthFailureTest.java
@@ -20,7 +20,7 @@ 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.mongodb3.MongoDbTestRule.LoggingTarget;
+import org.apache.logging.log4j.mongodb3.MongoDb3TestRule.LoggingTarget;
 import org.apache.logging.log4j.test.AvailablePortSystemPropertyTestRule;
 import org.apache.logging.log4j.test.RuleChainFactory;
 import org.bson.Document;
@@ -42,15 +42,15 @@ import com.mongodb.client.MongoDatabase;
  */
 @Ignore("TODO Set up the log4j user in MongoDB")
 @Category(Appenders.MongoDb.class)
-public class MongoDbAuthFailureTest {
+public class MongoDb3AuthFailureTest {
 
     private static LoggerContextRule loggerContextTestRule = new LoggerContextRule("log4j2-mongodb-auth-failure.xml");
 
     private static final AvailablePortSystemPropertyTestRule mongoDbPortTestRule = AvailablePortSystemPropertyTestRule
-            .create(TestConstants.SYS_PROP_NAME_PORT);
+            .create(MongoDb3TestConstants.SYS_PROP_NAME_PORT);
 
-    private static final MongoDbTestRule mongoDbTestRule = new MongoDbTestRule(mongoDbPortTestRule.getName(),
-            MongoDbAuthFailureTest.class, LoggingTarget.NULL);
+    private static final MongoDb3TestRule mongoDbTestRule = new MongoDb3TestRule(mongoDbPortTestRule.getName(),
+            MongoDb3AuthFailureTest.class, LoggingTarget.NULL);
 
     @ClassRule
     public static RuleChain ruleChain = RuleChainFactory.create(mongoDbPortTestRule, mongoDbTestRule,
diff --git a/log4j-mongodb3/src/test/java/org/apache/logging/log4j/mongodb3/MongoDbCappedTest.java b/log4j-mongodb3/src/test/java/org/apache/logging/log4j/mongodb3/MongoDb3CappedTest.java
similarity index 88%
copy from log4j-mongodb3/src/test/java/org/apache/logging/log4j/mongodb3/MongoDbCappedTest.java
copy to log4j-mongodb3/src/test/java/org/apache/logging/log4j/mongodb3/MongoDb3CappedTest.java
index 7611284..f03af5f 100644
--- a/log4j-mongodb3/src/test/java/org/apache/logging/log4j/mongodb3/MongoDbCappedTest.java
+++ b/log4j-mongodb3/src/test/java/org/apache/logging/log4j/mongodb3/MongoDb3CappedTest.java
@@ -20,7 +20,7 @@ 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.mongodb3.MongoDbTestRule.LoggingTarget;
+import org.apache.logging.log4j.mongodb3.MongoDb3TestRule.LoggingTarget;
 import org.apache.logging.log4j.test.AvailablePortSystemPropertyTestRule;
 import org.apache.logging.log4j.test.RuleChainFactory;
 import org.bson.Document;
@@ -38,15 +38,15 @@ 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 MongoDbCappedTest {
+public class MongoDb3CappedTest {
 
     private static LoggerContextRule loggerContextTestRule = new LoggerContextRule("log4j2-mongodb-capped.xml");
 
     private static final AvailablePortSystemPropertyTestRule mongoDbPortTestRule = AvailablePortSystemPropertyTestRule
-            .create(TestConstants.SYS_PROP_NAME_PORT);
+            .create(MongoDb3TestConstants.SYS_PROP_NAME_PORT);
 
-    private static final MongoDbTestRule mongoDbTestRule = new MongoDbTestRule(mongoDbPortTestRule.getName(),
-            MongoDbCappedTest.class, LoggingTarget.NULL);
+    private static final MongoDb3TestRule mongoDbTestRule = new MongoDb3TestRule(mongoDbPortTestRule.getName(),
+            MongoDb3CappedTest.class, LoggingTarget.NULL);
 
     @ClassRule
     public static RuleChain ruleChain = RuleChainFactory.create(mongoDbPortTestRule, mongoDbTestRule,
diff --git a/log4j-mongodb3/src/test/java/org/apache/logging/log4j/mongodb3/MongoDbMapMessageTest.java b/log4j-mongodb3/src/test/java/org/apache/logging/log4j/mongodb3/MongoDb3MapMessageTest.java
similarity index 89%
copy from log4j-mongodb3/src/test/java/org/apache/logging/log4j/mongodb3/MongoDbMapMessageTest.java
copy to log4j-mongodb3/src/test/java/org/apache/logging/log4j/mongodb3/MongoDb3MapMessageTest.java
index cceb8ef..9a45ede 100644
--- a/log4j-mongodb3/src/test/java/org/apache/logging/log4j/mongodb3/MongoDbMapMessageTest.java
+++ b/log4j-mongodb3/src/test/java/org/apache/logging/log4j/mongodb3/MongoDb3MapMessageTest.java
@@ -21,7 +21,7 @@ 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.mongodb3.MongoDbTestRule.LoggingTarget;
+import org.apache.logging.log4j.mongodb3.MongoDb3TestRule.LoggingTarget;
 import org.apache.logging.log4j.test.AvailablePortSystemPropertyTestRule;
 import org.apache.logging.log4j.test.RuleChainFactory;
 import org.bson.Document;
@@ -39,15 +39,15 @@ 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 MongoDbMapMessageTest {
+public class MongoDb3MapMessageTest {
 
     private static LoggerContextRule loggerContextTestRule = new LoggerContextRule("log4j2-mongodb-map-message.xml");
 
     private static final AvailablePortSystemPropertyTestRule mongoDbPortTestRule = AvailablePortSystemPropertyTestRule
-            .create(TestConstants.SYS_PROP_NAME_PORT);
+            .create(MongoDb3TestConstants.SYS_PROP_NAME_PORT);
 
-    private static final MongoDbTestRule mongoDbTestRule = new MongoDbTestRule(mongoDbPortTestRule.getName(),
-            MongoDbMapMessageTest.class, LoggingTarget.NULL);
+    private static final MongoDb3TestRule mongoDbTestRule = new MongoDb3TestRule(mongoDbPortTestRule.getName(),
+            MongoDb3MapMessageTest.class, LoggingTarget.NULL);
 
     @ClassRule
     public static RuleChain ruleChain = RuleChainFactory.create(mongoDbPortTestRule, mongoDbTestRule,
diff --git a/log4j-mongodb3/src/test/java/org/apache/logging/log4j/mongodb3/MongoDbTest.java b/log4j-mongodb3/src/test/java/org/apache/logging/log4j/mongodb3/MongoDb3Test.java
similarity index 89%
copy from log4j-mongodb3/src/test/java/org/apache/logging/log4j/mongodb3/MongoDbTest.java
copy to log4j-mongodb3/src/test/java/org/apache/logging/log4j/mongodb3/MongoDb3Test.java
index 2b93b7b..dd0bcd2 100644
--- a/log4j-mongodb3/src/test/java/org/apache/logging/log4j/mongodb3/MongoDbTest.java
+++ b/log4j-mongodb3/src/test/java/org/apache/logging/log4j/mongodb3/MongoDb3Test.java
@@ -20,7 +20,7 @@ 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.mongodb3.MongoDbTestRule.LoggingTarget;
+import org.apache.logging.log4j.mongodb3.MongoDb3TestRule.LoggingTarget;
 import org.apache.logging.log4j.test.AvailablePortSystemPropertyTestRule;
 import org.apache.logging.log4j.test.RuleChainFactory;
 import org.bson.Document;
@@ -38,15 +38,15 @@ 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 MongoDbTest {
+public class MongoDb3Test {
 
     private static LoggerContextRule loggerContextTestRule = new LoggerContextRule("log4j2-mongodb.xml");
 
     private static final AvailablePortSystemPropertyTestRule mongoDbPortTestRule = AvailablePortSystemPropertyTestRule
-            .create(TestConstants.SYS_PROP_NAME_PORT);
+            .create(MongoDb3TestConstants.SYS_PROP_NAME_PORT);
 
-    private static final MongoDbTestRule mongoDbTestRule = new MongoDbTestRule(mongoDbPortTestRule.getName(),
-            MongoDbTest.class, LoggingTarget.NULL);
+    private static final MongoDb3TestRule mongoDbTestRule = new MongoDb3TestRule(mongoDbPortTestRule.getName(),
+            MongoDb3Test.class, LoggingTarget.NULL);
 
     @ClassRule
     public static RuleChain ruleChain = RuleChainFactory.create(mongoDbPortTestRule, mongoDbTestRule,
diff --git a/log4j-mongodb3/src/test/java/org/apache/logging/log4j/mongodb3/TestConstants.java b/log4j-mongodb3/src/test/java/org/apache/logging/log4j/mongodb3/MongoDb3TestConstants.java
similarity index 96%
rename from log4j-mongodb3/src/test/java/org/apache/logging/log4j/mongodb3/TestConstants.java
rename to log4j-mongodb3/src/test/java/org/apache/logging/log4j/mongodb3/MongoDb3TestConstants.java
index 3e7e0f3..cfae3e4 100644
--- a/log4j-mongodb3/src/test/java/org/apache/logging/log4j/mongodb3/TestConstants.java
+++ b/log4j-mongodb3/src/test/java/org/apache/logging/log4j/mongodb3/MongoDb3TestConstants.java
@@ -17,7 +17,7 @@
 
 package org.apache.logging.log4j.mongodb3;
 
-public class TestConstants {
+public class MongoDb3TestConstants {
 
     public static final String SYS_PROP_NAME_PORT = "MongoDBTestPort";
 
diff --git a/log4j-mongodb3/src/test/java/org/apache/logging/log4j/mongodb3/MongoDbTestRule.java b/log4j-mongodb3/src/test/java/org/apache/logging/log4j/mongodb3/MongoDb3TestRule.java
similarity index 97%
rename from log4j-mongodb3/src/test/java/org/apache/logging/log4j/mongodb3/MongoDbTestRule.java
rename to log4j-mongodb3/src/test/java/org/apache/logging/log4j/mongodb3/MongoDb3TestRule.java
index 51bbcc2..51c2012 100644
--- a/log4j-mongodb3/src/test/java/org/apache/logging/log4j/mongodb3/MongoDbTestRule.java
+++ b/log4j-mongodb3/src/test/java/org/apache/logging/log4j/mongodb3/MongoDb3TestRule.java
@@ -46,7 +46,7 @@ import de.flapdoodle.embed.process.runtime.Network;
  * 
  * TODO Move this class to Apache Commons Testing.
  */
-public class MongoDbTestRule implements TestRule {
+public class MongoDb3TestRule implements TestRule {
 
     public enum LoggingTarget {
         CONSOLE, NULL;
@@ -68,7 +68,7 @@ public class MongoDbTestRule implements TestRule {
         }
         switch (loggingTarget) {
         case NULL:
-            final Logger logger = LoggerFactory.getLogger(MongoDbTestRule.class.getName());
+            final Logger logger = LoggerFactory.getLogger(MongoDb3TestRule.class.getName());
             final IRuntimeConfig runtimeConfig = new RuntimeConfigBuilder()
             // @formatter:off
                 .defaultsWithLogger(Command.MongoD, logger)
@@ -110,7 +110,7 @@ public class MongoDbTestRule implements TestRule {
      * @param defaultLoggingTarget
      *            The logging target.
      */
-    public MongoDbTestRule(final String portSystemPropertyName, final Class<?> clazz,
+    public MongoDb3TestRule(final String portSystemPropertyName, final Class<?> clazz,
             final LoggingTarget defaultLoggingTarget) {
         this.portSystemPropertyName = Objects.requireNonNull(portSystemPropertyName, "portSystemPropertyName");
         this.loggingTarget = LoggingTarget.getLoggingTarget(clazz.getName() + "." + LoggingTarget.class.getSimpleName(),
diff --git a/log4j-mongodb3/src/test/java/org/apache/logging/log4j/mongodb3/MongoDbTestTestRuleTest.java b/log4j-mongodb3/src/test/java/org/apache/logging/log4j/mongodb3/MongoDb3TestTestRuleTest.java
similarity index 87%
rename from log4j-mongodb3/src/test/java/org/apache/logging/log4j/mongodb3/MongoDbTestTestRuleTest.java
rename to log4j-mongodb3/src/test/java/org/apache/logging/log4j/mongodb3/MongoDb3TestTestRuleTest.java
index e19980b..ccdf0c8 100644
--- a/log4j-mongodb3/src/test/java/org/apache/logging/log4j/mongodb3/MongoDbTestTestRuleTest.java
+++ b/log4j-mongodb3/src/test/java/org/apache/logging/log4j/mongodb3/MongoDb3TestTestRuleTest.java
@@ -19,7 +19,7 @@ package org.apache.logging.log4j.mongodb3;
 
 import org.apache.commons.lang3.JavaVersion;
 import org.apache.commons.lang3.SystemUtils;
-import org.apache.logging.log4j.mongodb3.MongoDbTestRule.LoggingTarget;
+import org.apache.logging.log4j.mongodb3.MongoDb3TestRule.LoggingTarget;
 import org.apache.logging.log4j.test.AvailablePortSystemPropertyTestRule;
 import org.apache.logging.log4j.test.RuleChainFactory;
 import org.junit.Assert;
@@ -37,13 +37,13 @@ import com.mongodb.client.MongoIterable;
  * The test framework {@code de.flapdoodle.embed.mongo} requires Java 8.
  * </p>
  */
-public class MongoDbTestTestRuleTest {
+public class MongoDb3TestTestRuleTest {
 
     private static final AvailablePortSystemPropertyTestRule mongoDbPortTestRule = AvailablePortSystemPropertyTestRule
-            .create(TestConstants.SYS_PROP_NAME_PORT);
+            .create(MongoDb3TestConstants.SYS_PROP_NAME_PORT);
 
-    private static final MongoDbTestRule mongoDbTestRule = new MongoDbTestRule(mongoDbPortTestRule.getName(),
-            MongoDbTestTestRuleTest.class, LoggingTarget.NULL);
+    private static final MongoDb3TestRule mongoDbTestRule = new MongoDb3TestRule(mongoDbPortTestRule.getName(),
+            MongoDb3TestTestRuleTest.class, LoggingTarget.NULL);
 
     @ClassRule
     public static RuleChain mongoDbChain = RuleChainFactory.create(mongoDbPortTestRule, mongoDbTestRule);
diff --git a/log4j-mongodb2/pom.xml b/log4j-mongodb4/pom.xml
similarity index 92%
rename from log4j-mongodb2/pom.xml
rename to log4j-mongodb4/pom.xml
index b3b678b..bbd9629 100644
--- a/log4j-mongodb2/pom.xml
+++ b/log4j-mongodb4/pom.xml
@@ -24,16 +24,16 @@
   </parent>
   <modelVersion>4.0.0</modelVersion>
 
-  <artifactId>log4j-mongodb2</artifactId>
-  <name>Apache Log4j MongoDB 2</name>
+  <artifactId>log4j-mongodb4</artifactId>
+  <name>Apache Log4j MongoDB 4</name>
   <description>
-    MongoDB appender for Log4j using the MongoDB 2 driver API.
+    MongoDB appender for Log4j using the MongoDB 4 driver API.
   </description>
   <properties>
     <log4jParentDir>${basedir}/..</log4jParentDir>
-    <docLabel>MongoDB 2 Documentation</docLabel>
-    <projectDir>/log4j-mongodb2</projectDir>
-    <module.name>org.apache.logging.log4j.mongodb2</module.name>
+    <docLabel>MongoDB 4 Documentation</docLabel>
+    <projectDir>/log4j-mongodb4</projectDir>
+    <module.name>org.apache.logging.log4j.mongodb4</module.name>
   </properties>
 
   <dependencies>
@@ -43,7 +43,13 @@
     </dependency>
     <dependency>
       <groupId>org.mongodb</groupId>
-      <artifactId>mongo-java-driver</artifactId>
+      <artifactId>mongodb-driver-sync</artifactId>
+      <version>${mongodb4.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.mongodb</groupId>
+      <artifactId>bson</artifactId>
+      <version>${mongodb4.version}</version>
     </dependency>
     <!-- Test Dependencies -->
     <dependency>
@@ -59,15 +65,12 @@
       <groupId>org.apache.logging.log4j</groupId>
       <artifactId>log4j-api</artifactId>
       <type>test-jar</type>
+      <scope>test</scope>
     </dependency>
     <dependency>
       <groupId>org.apache.logging.log4j</groupId>
       <artifactId>log4j-core</artifactId>
       <type>test-jar</type>
-    </dependency>
-    <dependency>
-      <groupId>org.apache.logging.log4j</groupId>
-      <artifactId>log4j-slf4j-impl</artifactId>
       <scope>test</scope>
     </dependency>
     <dependency>
diff --git a/log4j-mongodb3/src/main/java/org/apache/logging/log4j/mongodb3/MongoDbConnection.java b/log4j-mongodb4/src/main/java/org/apache/logging/log4j/mongodb4/MongoDb4Connection.java
similarity index 61%
rename from log4j-mongodb3/src/main/java/org/apache/logging/log4j/mongodb3/MongoDbConnection.java
rename to log4j-mongodb4/src/main/java/org/apache/logging/log4j/mongodb4/MongoDb4Connection.java
index 34d0613..509003f 100644
--- a/log4j-mongodb3/src/main/java/org/apache/logging/log4j/mongodb3/MongoDbConnection.java
+++ b/log4j-mongodb4/src/main/java/org/apache/logging/log4j/mongodb4/MongoDb4Connection.java
@@ -14,7 +14,7 @@
  * See the license for the specific language governing permissions and
  * limitations under the license.
  */
-package org.apache.logging.log4j.mongodb3;
+package org.apache.logging.log4j.mongodb4;
 
 import org.apache.logging.log4j.Logger;
 import org.apache.logging.log4j.core.appender.AppenderLoggingException;
@@ -24,16 +24,18 @@ import org.apache.logging.log4j.core.appender.nosql.NoSqlObject;
 import org.apache.logging.log4j.status.StatusLogger;
 import org.bson.Document;
 
-import com.mongodb.MongoClient;
+import com.mongodb.ConnectionString;
 import com.mongodb.MongoException;
+import com.mongodb.client.MongoClient;
 import com.mongodb.client.MongoCollection;
 import com.mongodb.client.MongoDatabase;
 import com.mongodb.client.model.CreateCollectionOptions;
+import com.mongodb.client.result.InsertOneResult;
 
 /**
  * The MongoDB implementation of {@link NoSqlConnection}.
  */
-public final class MongoDbConnection extends AbstractNoSqlConnection<Document, MongoDbDocumentObject> {
+public final class MongoDb4Connection extends AbstractNoSqlConnection<Document, MongoDb4DocumentObject> {
 
     private static final Logger LOGGER = StatusLogger.getLogger();
 
@@ -42,29 +44,33 @@ public final class MongoDbConnection extends AbstractNoSqlConnection<Document, M
         try {
             LOGGER.debug("Gettting collection '{}'...", collectionName);
             // throws IllegalArgumentException if collectionName is invalid
-            return database.getCollection(collectionName);
+            final MongoCollection<Document> found = database.getCollection(collectionName);
+            LOGGER.debug("Got collection {}", found);
+            return found;
         } catch (final IllegalStateException e) {
             LOGGER.debug("Collection '{}' does not exist.", collectionName);
-            final CreateCollectionOptions options = new CreateCollectionOptions()
-            // @formatter:off
-                    .capped(isCapped)
+            final CreateCollectionOptions options = new CreateCollectionOptions().capped(isCapped)
                     .sizeInBytes(sizeInBytes);
-            // @formatter:on
-            LOGGER.debug("Creating collection {} (capped = {}, sizeInBytes = {})", collectionName, isCapped,
-                    sizeInBytes);
+            LOGGER.debug("Creating collection '{}' with options {}...", collectionName, options);
             database.createCollection(collectionName, options);
-            return database.getCollection(collectionName);
+            LOGGER.debug("Created collection.");
+            final MongoCollection<Document> created = database.getCollection(collectionName);
+            LOGGER.debug("Got created collection {}", created);
+            return created;
         }
 
     }
 
+    private final ConnectionString connectionString;
     private final MongoCollection<Document> collection;
     private final MongoClient mongoClient;
 
-    public MongoDbConnection(final MongoClient mongoClient, final MongoDatabase mongoDatabase,
-            final String collectionName, final boolean isCapped, final Integer sizeInBytes) {
+    public MongoDb4Connection(final ConnectionString connectionString, final MongoClient mongoClient,
+            final MongoDatabase mongoDatabase, final boolean isCapped, final Integer sizeInBytes) {
+        this.connectionString = connectionString;
         this.mongoClient = mongoClient;
-        this.collection = getOrCreateMongoCollection(mongoDatabase, collectionName, isCapped, sizeInBytes);
+        this.collection = getOrCreateMongoCollection(mongoDatabase, connectionString.getCollection(), isCapped,
+                sizeInBytes);
     }
 
     @Override
@@ -74,25 +80,32 @@ public final class MongoDbConnection extends AbstractNoSqlConnection<Document, M
     }
 
     @Override
-    public MongoDbDocumentObject[] createList(final int length) {
-        return new MongoDbDocumentObject[length];
+    public MongoDb4DocumentObject[] createList(final int length) {
+        return new MongoDb4DocumentObject[length];
     }
 
     @Override
-    public MongoDbDocumentObject createObject() {
-        return new MongoDbDocumentObject();
+    public MongoDb4DocumentObject createObject() {
+        return new MongoDb4DocumentObject();
     }
 
     @Override
     public void insertObject(final NoSqlObject<Document> object) {
         try {
             final Document unwrapped = object.unwrap();
-            LOGGER.debug("Inserting object {}", unwrapped);
-            this.collection.insertOne(unwrapped);
+            LOGGER.debug("Inserting BSON Document {}", unwrapped);
+            InsertOneResult insertOneResult = this.collection.insertOne(unwrapped);
+            LOGGER.debug("Insert MongoDb result {}", insertOneResult);
         } catch (final MongoException e) {
             throw new AppenderLoggingException("Failed to write log event to MongoDB due to error: " + e.getMessage(),
                     e);
         }
     }
 
+    @Override
+    public String toString() {
+        return String.format("Mongo4Connection [connectionString=%s, collection=%s, mongoClient=%s]", connectionString,
+                collection, mongoClient);
+    }
+
 }
diff --git a/log4j-mongodb2/src/main/java/org/apache/logging/log4j/mongodb2/MongoDbObject.java b/log4j-mongodb4/src/main/java/org/apache/logging/log4j/mongodb4/MongoDb4DocumentObject.java
similarity index 50%
rename from log4j-mongodb2/src/main/java/org/apache/logging/log4j/mongodb2/MongoDbObject.java
rename to log4j-mongodb4/src/main/java/org/apache/logging/log4j/mongodb4/MongoDb4DocumentObject.java
index 28a35cd..707479d 100644
--- a/log4j-mongodb2/src/main/java/org/apache/logging/log4j/mongodb2/MongoDbObject.java
+++ b/log4j-mongodb4/src/main/java/org/apache/logging/log4j/mongodb4/MongoDb4DocumentObject.java
@@ -14,53 +14,51 @@
  * See the license for the specific language governing permissions and
  * limitations under the license.
  */
-package org.apache.logging.log4j.mongodb2;
+package org.apache.logging.log4j.mongodb4;
 
-import java.util.Collections;
+import java.util.Arrays;
 
 import org.apache.logging.log4j.core.appender.nosql.NoSqlObject;
-
-import com.mongodb.BasicDBList;
-import com.mongodb.BasicDBObject;
+import org.bson.Document;
 
 /**
- * The MongoDB implementation of {@link NoSqlObject}.
+ * The MongoDB implementation of {@link NoSqlObject} typed to a BSON
+ * {@link Document}.
  */
-public final class MongoDbObject implements NoSqlObject<BasicDBObject> {
-    private final BasicDBObject mongoObject;
+public final class MongoDb4DocumentObject implements NoSqlObject<Document> {
+    private final Document document;
 
-    public MongoDbObject() {
-        this.mongoObject = new BasicDBObject();
+    public MongoDb4DocumentObject() {
+        this.document = new Document();
     }
 
     @Override
-    public void set(final String field, final NoSqlObject<BasicDBObject> value) {
-        this.mongoObject.append(field, value.unwrap());
+    public void set(final String field, final NoSqlObject<Document> value) {
+        this.document.append(field, value.unwrap());
     }
 
     @Override
-    public void set(final String field, final NoSqlObject<BasicDBObject>[] values) {
-        final BasicDBList list = new BasicDBList();
-        for (final NoSqlObject<BasicDBObject> value : values) {
-            list.add(value.unwrap());
-        }
-        this.mongoObject.append(field, list);
+    public void set(final String field, final NoSqlObject<Document>[] values) {
+        this.document.append(field, Arrays.asList(values));
     }
 
     @Override
     public void set(final String field, final Object value) {
-        this.mongoObject.append(field, value);
+        this.document.append(field, value);
     }
 
     @Override
     public void set(final String field, final Object[] values) {
-        final BasicDBList list = new BasicDBList();
-        Collections.addAll(list, values);
-        this.mongoObject.append(field, list);
+        this.document.append(field, Arrays.asList(values));
+    }
+
+    @Override
+    public String toString() {
+        return String.format("Mongo4DocumentObject [document=%s]", document);
     }
 
     @Override
-    public BasicDBObject unwrap() {
-        return this.mongoObject;
+    public Document unwrap() {
+        return this.document;
     }
 }
diff --git a/log4j-mongodb3/src/main/java/org/apache/logging/log4j/mongodb3/LevelCodec.java b/log4j-mongodb4/src/main/java/org/apache/logging/log4j/mongodb4/MongoDb4LevelCodec.java
similarity index 86%
rename from log4j-mongodb3/src/main/java/org/apache/logging/log4j/mongodb3/LevelCodec.java
rename to log4j-mongodb4/src/main/java/org/apache/logging/log4j/mongodb4/MongoDb4LevelCodec.java
index f900863..ea1b5ba 100644
--- a/log4j-mongodb3/src/main/java/org/apache/logging/log4j/mongodb3/LevelCodec.java
+++ b/log4j-mongodb4/src/main/java/org/apache/logging/log4j/mongodb4/MongoDb4LevelCodec.java
@@ -15,7 +15,7 @@
  * limitations under the license.
  */
 
-package org.apache.logging.log4j.mongodb3;
+package org.apache.logging.log4j.mongodb4;
 
 import org.apache.logging.log4j.Level;
 import org.bson.BsonReader;
@@ -25,17 +25,15 @@ import org.bson.codecs.DecoderContext;
 import org.bson.codecs.EncoderContext;
 
 /**
- * A BSON Codec for Log4j {@link Level}s.
+ * A BSON {@link Codec} for Log4j {@link Level}s.
  */
-public class LevelCodec implements Codec<Level> {
+public class MongoDb4LevelCodec implements Codec<Level> {
 
     /**
      * The singleton instance.
-     *
-     * @since 2.14.0
      */
-    public static final LevelCodec INSTANCE = new LevelCodec();
-    
+    public static final MongoDb4LevelCodec INSTANCE = new MongoDb4LevelCodec();
+
     @Override
     public Level decode(final BsonReader reader, final DecoderContext decoderContext) {
         return Level.getLevel(reader.readString());
diff --git a/log4j-mongodb4/src/main/java/org/apache/logging/log4j/mongodb4/MongoDb4Provider.java b/log4j-mongodb4/src/main/java/org/apache/logging/log4j/mongodb4/MongoDb4Provider.java
new file mode 100644
index 0000000..3f7fb2f
--- /dev/null
+++ b/log4j-mongodb4/src/main/java/org/apache/logging/log4j/mongodb4/MongoDb4Provider.java
@@ -0,0 +1,132 @@
+/*
+ * 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.mongodb4;
+
+import org.apache.logging.log4j.Logger;
+import org.apache.logging.log4j.core.Core;
+import org.apache.logging.log4j.core.appender.nosql.NoSqlProvider;
+import org.apache.logging.log4j.core.config.plugins.PluginBuilderAttribute;
+import org.apache.logging.log4j.core.config.plugins.PluginBuilderFactory;
+import org.apache.logging.log4j.core.filter.AbstractFilterable;
+import org.apache.logging.log4j.plugins.Plugin;
+import org.apache.logging.log4j.plugins.validation.constraints.Required;
+import org.apache.logging.log4j.status.StatusLogger;
+import org.bson.codecs.configuration.CodecRegistries;
+import org.bson.codecs.configuration.CodecRegistry;
+
+import com.mongodb.ConnectionString;
+import com.mongodb.MongoClientSettings;
+import com.mongodb.client.MongoClient;
+import com.mongodb.client.MongoClients;
+import com.mongodb.client.MongoDatabase;
+
+/**
+ * The MongoDB implementation of {@link NoSqlProvider} using the MongoDB driver
+ * version 4 API.
+ */
+@Plugin(name = "MongoDb4", category = Core.CATEGORY_NAME, printObject = true)
+public final class MongoDb4Provider implements NoSqlProvider<MongoDb4Connection> {
+
+    public static class Builder<B extends Builder<B>> extends AbstractFilterable.Builder<B>
+            implements org.apache.logging.log4j.core.util.Builder<MongoDb4Provider> {
+
+        @PluginBuilderAttribute(value = "connection")
+        @Required(message = "No connection string provided")
+        private String connection;
+
+        @PluginBuilderAttribute
+        private int collectionSize = DEFAULT_COLLECTION_SIZE;
+
+        @PluginBuilderAttribute("capped")
+        private boolean capped = false;
+
+        @Override
+        public MongoDb4Provider build() {
+            return new MongoDb4Provider(connection, capped, collectionSize);
+        }
+
+        public B setCapped(final boolean isCapped) {
+            this.capped = isCapped;
+            return asBuilder();
+        }
+
+        public B setCollectionSize(final int collectionSize) {
+            this.collectionSize = collectionSize;
+            return asBuilder();
+        }
+    }
+
+    private static final Logger LOGGER = StatusLogger.getLogger();
+
+    // @formatter:off
+    private static final CodecRegistry CODEC_REGISTRIES = CodecRegistries.fromRegistries(
+            MongoClientSettings.getDefaultCodecRegistry(),
+            CodecRegistries.fromCodecs(MongoDb4LevelCodec.INSTANCE));
+    // @formatter:on
+
+    // TODO Where does this number come from?
+    private static final int DEFAULT_COLLECTION_SIZE = 536_870_912;
+
+    @PluginBuilderFactory
+    public static <B extends Builder<B>> B newBuilder() {
+        return new Builder<B>().asBuilder();
+    }
+
+    private final Integer collectionSize;
+    private final boolean isCapped;
+    private final MongoClient mongoClient;
+    private final MongoDatabase mongoDatabase;
+    private final ConnectionString connectionString;
+
+    private MongoDb4Provider(final String connectionStringSource, final boolean isCapped,
+            final Integer collectionSize) {
+        LOGGER.debug("Creating ConnectionString {}...", connectionStringSource);
+        this.connectionString = new ConnectionString(connectionStringSource);
+        LOGGER.debug("Created ConnectionString {}", connectionString);
+        LOGGER.debug("Creating MongoClientSettings...");
+        // @formatter:off
+        final MongoClientSettings settings = MongoClientSettings.builder()
+                .applyConnectionString(this.connectionString)
+                .codecRegistry(CODEC_REGISTRIES)
+                .build();
+        // @formatter:on
+        LOGGER.debug("Created MongoClientSettings {}", settings);
+        LOGGER.debug("Creating MongoClient {}...", settings);
+        this.mongoClient = MongoClients.create(settings);
+        LOGGER.debug("Created MongoClient {}", mongoClient);
+        String databaseName = this.connectionString.getDatabase();
+        LOGGER.debug("Getting MongoDatabase {}...", databaseName);
+        this.mongoDatabase = this.mongoClient.getDatabase(databaseName);
+        LOGGER.debug("Got MongoDatabase {}", mongoDatabase);
+        this.isCapped = isCapped;
+        this.collectionSize = collectionSize;
+    }
+
+    @Override
+    public MongoDb4Connection getConnection() {
+        return new MongoDb4Connection(connectionString, mongoClient, mongoDatabase, isCapped, collectionSize);
+    }
+
+    @Override
+    public String toString() {
+        return String.format(
+                "%s [connectionString=%s, collectionSize=%s, isCapped=%s, mongoClient=%s, mongoDatabase=%s]",
+                MongoDb4Provider.class.getSimpleName(), connectionString, collectionSize, isCapped, mongoClient,
+                mongoDatabase);
+    }
+
+}
diff --git a/log4j-mongodb2/src/main/java/org/apache/logging/log4j/mongodb2/package-info.java b/log4j-mongodb4/src/main/java/org/apache/logging/log4j/mongodb4/package-info.java
similarity index 92%
rename from log4j-mongodb2/src/main/java/org/apache/logging/log4j/mongodb2/package-info.java
rename to log4j-mongodb4/src/main/java/org/apache/logging/log4j/mongodb4/package-info.java
index bf111af..8f380b3 100644
--- a/log4j-mongodb2/src/main/java/org/apache/logging/log4j/mongodb2/package-info.java
+++ b/log4j-mongodb4/src/main/java/org/apache/logging/log4j/mongodb4/package-info.java
@@ -15,6 +15,7 @@
  * limitations under the license.
  */
 /**
- * The classes in this package contain the MongoDB provider for the NoSQL Appender.
+ * The classes in this package contain the MongoDB provider for the NoSQL
+ * Appender.
  */
-package org.apache.logging.log4j.mongodb2;
+package org.apache.logging.log4j.mongodb4;
diff --git a/log4j-mongodb2/src/site/markdown/index.md.vm b/log4j-mongodb4/src/site/markdown/index.md.vm
similarity index 97%
rename from log4j-mongodb2/src/site/markdown/index.md.vm
rename to log4j-mongodb4/src/site/markdown/index.md.vm
index 0d1eb7a..1bdd5a5 100644
--- a/log4j-mongodb2/src/site/markdown/index.md.vm
+++ b/log4j-mongodb4/src/site/markdown/index.md.vm
@@ -30,7 +30,7 @@ $h1 MongoDB appender
       <dependency>
         <groupId>org.mongodb</groupId>
         <artifactId>mongo-java-driver</artifactId>
-        <version>2.14.3</version>
+        <version>2.12.3</version>
       </dependency>
     </dependencies>
   </dependencyManagement>
diff --git a/log4j-mongodb2/src/site/site.xml b/log4j-mongodb4/src/site/site.xml
similarity index 98%
rename from log4j-mongodb2/src/site/site.xml
rename to log4j-mongodb4/src/site/site.xml
index f5db26e..54ea9be 100644
--- a/log4j-mongodb2/src/site/site.xml
+++ b/log4j-mongodb4/src/site/site.xml
@@ -15,7 +15,7 @@
  limitations under the License.
 
 -->
-<project name="Log4j MongoDB 2.x Appender"
+<project name="Log4j MongoDB Appender"
          xmlns="http://maven.apache.org/DECORATION/1.4.0"
          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          xsi:schemaLocation="http://maven.apache.org/DECORATION/1.4.0 http://maven.apache.org/xsd/decoration-1.4.0.xsd">
diff --git a/log4j-mongodb2/src/test/java/org/apache/logging/log4j/mongodb2/MongoDbAuthFailureTest.java b/log4j-mongodb4/src/test/java/org/apache/logging/log4j/mongodb4/MongoDb4AuthFailureTest.java
similarity index 68%
rename from log4j-mongodb2/src/test/java/org/apache/logging/log4j/mongodb2/MongoDbAuthFailureTest.java
rename to log4j-mongodb4/src/test/java/org/apache/logging/log4j/mongodb4/MongoDb4AuthFailureTest.java
index a7c4a1d..c84d108 100644
--- a/log4j-mongodb2/src/test/java/org/apache/logging/log4j/mongodb2/MongoDbAuthFailureTest.java
+++ b/log4j-mongodb4/src/test/java/org/apache/logging/log4j/mongodb4/MongoDb4AuthFailureTest.java
@@ -14,15 +14,16 @@
  * See the license for the specific language governing permissions and
  * limitations under the license.
  */
-package org.apache.logging.log4j.mongodb2;
+package org.apache.logging.log4j.mongodb4;
 
 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.mongodb2.MongoDbTestRule.LoggingTarget;
+import org.apache.logging.log4j.mongodb4.MongoDb4TestRule.LoggingTarget;
 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.Ignore;
@@ -30,26 +31,26 @@ import org.junit.Test;
 import org.junit.experimental.categories.Category;
 import org.junit.rules.RuleChain;
 
-import com.mongodb.DB;
-import com.mongodb.DBCollection;
-import com.mongodb.DBCursor;
-import com.mongodb.MongoClient;
+import com.mongodb.client.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}.
+ *
  *
  * TODO Set up the log4j user in MongoDB.
  */
 @Ignore("TODO Set up the log4j user in MongoDB")
 @Category(Appenders.MongoDb.class)
-public class MongoDbAuthFailureTest {
+public class MongoDb4AuthFailureTest {
 
     private static LoggerContextRule loggerContextTestRule = new LoggerContextRule("log4j2-mongodb-auth-failure.xml");
 
     private static final AvailablePortSystemPropertyTestRule mongoDbPortTestRule = AvailablePortSystemPropertyTestRule
-            .create(TestConstants.SYS_PROP_NAME_PORT);
+            .create(MongoDb4TestConstants.SYS_PROP_NAME_PORT);
 
-    private static final MongoDbTestRule mongoDbTestRule = new MongoDbTestRule(mongoDbPortTestRule.getName(), LoggingTarget.NULL);
+    private static final MongoDb4TestRule mongoDbTestRule = new MongoDb4TestRule(mongoDbPortTestRule.getName(),
+            MongoDb4AuthFailureTest.class, LoggingTarget.NULL);
 
     @ClassRule
     public static RuleChain ruleChain = RuleChainFactory.create(mongoDbPortTestRule, mongoDbTestRule,
@@ -59,17 +60,13 @@ public class MongoDbAuthFailureTest {
     public void test() {
         final Logger logger = LogManager.getLogger();
         logger.info("Hello log");
-        final MongoClient mongoClient = mongoDbTestRule.getMongoClient();
-        try {
-            final DB database = mongoClient.getDB("test");
+        try (final MongoClient mongoClient = mongoDbTestRule.getMongoClient()) {
+            final MongoDatabase database = mongoClient.getDatabase("testDb");
             Assert.assertNotNull(database);
-            final DBCollection collection = database.getCollection("applog");
+            final MongoCollection<Document> collection = database.getCollection("testCollection");
             Assert.assertNotNull(collection);
-            try (DBCursor cursor = collection.find()) {
-                Assert.assertFalse(cursor.hasNext());
-            }
-        } finally {
-            mongoClient.close();
+            final Document first = collection.find().first();
+            Assert.assertNull(first);
         }
     }
 }
diff --git a/log4j-mongodb3/src/test/java/org/apache/logging/log4j/mongodb3/MongoDbCappedTest.java b/log4j-mongodb4/src/test/java/org/apache/logging/log4j/mongodb4/MongoDb4CappedTest.java
similarity index 82%
rename from log4j-mongodb3/src/test/java/org/apache/logging/log4j/mongodb3/MongoDbCappedTest.java
rename to log4j-mongodb4/src/test/java/org/apache/logging/log4j/mongodb4/MongoDb4CappedTest.java
index 7611284..fcd7cd7 100644
--- a/log4j-mongodb3/src/test/java/org/apache/logging/log4j/mongodb3/MongoDbCappedTest.java
+++ b/log4j-mongodb4/src/test/java/org/apache/logging/log4j/mongodb4/MongoDb4CappedTest.java
@@ -14,13 +14,13 @@
  * See the license for the specific language governing permissions and
  * limitations under the license.
  */
-package org.apache.logging.log4j.mongodb3;
+package org.apache.logging.log4j.mongodb4;
 
 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.mongodb3.MongoDbTestRule.LoggingTarget;
+import org.apache.logging.log4j.mongodb4.MongoDb4TestRule.LoggingTarget;
 import org.apache.logging.log4j.test.AvailablePortSystemPropertyTestRule;
 import org.apache.logging.log4j.test.RuleChainFactory;
 import org.bson.Document;
@@ -30,23 +30,23 @@ import org.junit.Test;
 import org.junit.experimental.categories.Category;
 import org.junit.rules.RuleChain;
 
-import com.mongodb.MongoClient;
+import com.mongodb.client.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 MongoDbCappedTest {
+public class MongoDb4CappedTest {
 
     private static LoggerContextRule loggerContextTestRule = new LoggerContextRule("log4j2-mongodb-capped.xml");
 
     private static final AvailablePortSystemPropertyTestRule mongoDbPortTestRule = AvailablePortSystemPropertyTestRule
-            .create(TestConstants.SYS_PROP_NAME_PORT);
+            .create(MongoDb4TestConstants.SYS_PROP_NAME_PORT);
 
-    private static final MongoDbTestRule mongoDbTestRule = new MongoDbTestRule(mongoDbPortTestRule.getName(),
-            MongoDbCappedTest.class, LoggingTarget.NULL);
+    private static final MongoDb4TestRule mongoDbTestRule = new MongoDb4TestRule(mongoDbPortTestRule.getName(),
+            MongoDb4CappedTest.class, LoggingTarget.NULL);
 
     @ClassRule
     public static RuleChain ruleChain = RuleChainFactory.create(mongoDbPortTestRule, mongoDbTestRule,
@@ -57,9 +57,9 @@ public class MongoDbCappedTest {
         final Logger logger = LogManager.getLogger();
         logger.info("Hello log");
         try (final MongoClient mongoClient = mongoDbTestRule.getMongoClient()) {
-            final MongoDatabase database = mongoClient.getDatabase("test");
+            final MongoDatabase database = mongoClient.getDatabase("testDb");
             Assert.assertNotNull(database);
-            final MongoCollection<Document> collection = database.getCollection("applog");
+            final MongoCollection<Document> collection = database.getCollection("testCollection");
             Assert.assertNotNull(collection);
             final Document first = collection.find().first();
             Assert.assertNotNull(first);
diff --git a/log4j-mongodb3/src/test/java/org/apache/logging/log4j/mongodb3/MongoDbMapMessageTest.java b/log4j-mongodb4/src/test/java/org/apache/logging/log4j/mongodb4/MongoDb4MapMessageTest.java
similarity index 83%
rename from log4j-mongodb3/src/test/java/org/apache/logging/log4j/mongodb3/MongoDbMapMessageTest.java
rename to log4j-mongodb4/src/test/java/org/apache/logging/log4j/mongodb4/MongoDb4MapMessageTest.java
index cceb8ef..70ab9a7 100644
--- a/log4j-mongodb3/src/test/java/org/apache/logging/log4j/mongodb3/MongoDbMapMessageTest.java
+++ b/log4j-mongodb4/src/test/java/org/apache/logging/log4j/mongodb4/MongoDb4MapMessageTest.java
@@ -14,14 +14,14 @@
  * See the license for the specific language governing permissions and
  * limitations under the license.
  */
-package org.apache.logging.log4j.mongodb3;
+package org.apache.logging.log4j.mongodb4;
 
 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.mongodb3.MongoDbTestRule.LoggingTarget;
+import org.apache.logging.log4j.mongodb4.MongoDb4TestRule.LoggingTarget;
 import org.apache.logging.log4j.test.AvailablePortSystemPropertyTestRule;
 import org.apache.logging.log4j.test.RuleChainFactory;
 import org.bson.Document;
@@ -31,23 +31,23 @@ import org.junit.Test;
 import org.junit.experimental.categories.Category;
 import org.junit.rules.RuleChain;
 
-import com.mongodb.MongoClient;
+import com.mongodb.client.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 MongoDbMapMessageTest {
+public class MongoDb4MapMessageTest {
 
     private static LoggerContextRule loggerContextTestRule = new LoggerContextRule("log4j2-mongodb-map-message.xml");
 
     private static final AvailablePortSystemPropertyTestRule mongoDbPortTestRule = AvailablePortSystemPropertyTestRule
-            .create(TestConstants.SYS_PROP_NAME_PORT);
+            .create(MongoDb4TestConstants.SYS_PROP_NAME_PORT);
 
-    private static final MongoDbTestRule mongoDbTestRule = new MongoDbTestRule(mongoDbPortTestRule.getName(),
-            MongoDbMapMessageTest.class, LoggingTarget.NULL);
+    private static final MongoDb4TestRule mongoDbTestRule = new MongoDb4TestRule(mongoDbPortTestRule.getName(),
+            MongoDb4MapMessageTest.class, LoggingTarget.NULL);
 
     @ClassRule
     public static RuleChain ruleChain = RuleChainFactory.create(mongoDbPortTestRule, mongoDbTestRule,
@@ -62,9 +62,9 @@ public class MongoDbMapMessageTest {
         logger.info(mapMessage);
         //
         try (final MongoClient mongoClient = mongoDbTestRule.getMongoClient()) {
-            final MongoDatabase database = mongoClient.getDatabase("test");
+            final MongoDatabase database = mongoClient.getDatabase("testDb");
             Assert.assertNotNull(database);
-            final MongoCollection<Document> collection = database.getCollection("applog");
+            final MongoCollection<Document> collection = database.getCollection("testCollection");
             Assert.assertNotNull(collection);
             final Document first = collection.find().first();
             Assert.assertNotNull(first);
diff --git a/log4j-mongodb3/src/test/java/org/apache/logging/log4j/mongodb3/MongoDbTest.java b/log4j-mongodb4/src/test/java/org/apache/logging/log4j/mongodb4/MongoDb4Test.java
similarity index 82%
rename from log4j-mongodb3/src/test/java/org/apache/logging/log4j/mongodb3/MongoDbTest.java
rename to log4j-mongodb4/src/test/java/org/apache/logging/log4j/mongodb4/MongoDb4Test.java
index 2b93b7b..e814f1f 100644
--- a/log4j-mongodb3/src/test/java/org/apache/logging/log4j/mongodb3/MongoDbTest.java
+++ b/log4j-mongodb4/src/test/java/org/apache/logging/log4j/mongodb4/MongoDb4Test.java
@@ -14,13 +14,13 @@
  * See the license for the specific language governing permissions and
  * limitations under the license.
  */
-package org.apache.logging.log4j.mongodb3;
+package org.apache.logging.log4j.mongodb4;
 
 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.mongodb3.MongoDbTestRule.LoggingTarget;
+import org.apache.logging.log4j.mongodb4.MongoDb4TestRule.LoggingTarget;
 import org.apache.logging.log4j.test.AvailablePortSystemPropertyTestRule;
 import org.apache.logging.log4j.test.RuleChainFactory;
 import org.bson.Document;
@@ -30,23 +30,23 @@ import org.junit.Test;
 import org.junit.experimental.categories.Category;
 import org.junit.rules.RuleChain;
 
-import com.mongodb.MongoClient;
+import com.mongodb.client.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 MongoDbTest {
+public class MongoDb4Test {
 
     private static LoggerContextRule loggerContextTestRule = new LoggerContextRule("log4j2-mongodb.xml");
 
     private static final AvailablePortSystemPropertyTestRule mongoDbPortTestRule = AvailablePortSystemPropertyTestRule
-            .create(TestConstants.SYS_PROP_NAME_PORT);
+            .create(MongoDb4TestConstants.SYS_PROP_NAME_PORT);
 
-    private static final MongoDbTestRule mongoDbTestRule = new MongoDbTestRule(mongoDbPortTestRule.getName(),
-            MongoDbTest.class, LoggingTarget.NULL);
+    private static final MongoDb4TestRule mongoDbTestRule = new MongoDb4TestRule(mongoDbPortTestRule.getName(),
+            MongoDb4Test.class, LoggingTarget.NULL);
 
     @ClassRule
     public static RuleChain ruleChain = RuleChainFactory.create(mongoDbPortTestRule, mongoDbTestRule,
@@ -57,9 +57,9 @@ public class MongoDbTest {
         final Logger logger = LogManager.getLogger();
         logger.info("Hello log");
         try (final MongoClient mongoClient = mongoDbTestRule.getMongoClient()) {
-            final MongoDatabase database = mongoClient.getDatabase("test");
+            final MongoDatabase database = mongoClient.getDatabase("testDb");
             Assert.assertNotNull(database);
-            final MongoCollection<Document> collection = database.getCollection("applog");
+            final MongoCollection<Document> collection = database.getCollection("testCollection");
             Assert.assertNotNull(collection);
             final Document first = collection.find().first();
             Assert.assertNotNull(first);
diff --git a/log4j-mongodb2/src/test/java/org/apache/logging/log4j/mongodb2/TestConstants.java b/log4j-mongodb4/src/test/java/org/apache/logging/log4j/mongodb4/MongoDb4TestConstants.java
similarity index 91%
rename from log4j-mongodb2/src/test/java/org/apache/logging/log4j/mongodb2/TestConstants.java
rename to log4j-mongodb4/src/test/java/org/apache/logging/log4j/mongodb4/MongoDb4TestConstants.java
index 040209c..0d398f0 100644
--- a/log4j-mongodb2/src/test/java/org/apache/logging/log4j/mongodb2/TestConstants.java
+++ b/log4j-mongodb4/src/test/java/org/apache/logging/log4j/mongodb4/MongoDb4TestConstants.java
@@ -15,9 +15,9 @@
  * limitations under the license.
  */
 
-package org.apache.logging.log4j.mongodb2;
+package org.apache.logging.log4j.mongodb4;
 
-public class TestConstants {
+public class MongoDb4TestConstants {
 
     public static final String SYS_PROP_NAME_PORT = "MongoDBTestPort";
 
diff --git a/log4j-mongodb2/src/test/java/org/apache/logging/log4j/mongodb2/MongoDbTestRule.java b/log4j-mongodb4/src/test/java/org/apache/logging/log4j/mongodb4/MongoDb4TestRule.java
similarity index 75%
rename from log4j-mongodb2/src/test/java/org/apache/logging/log4j/mongodb2/MongoDbTestRule.java
rename to log4j-mongodb4/src/test/java/org/apache/logging/log4j/mongodb4/MongoDb4TestRule.java
index acab7ba..035ef53 100644
--- a/log4j-mongodb2/src/test/java/org/apache/logging/log4j/mongodb2/MongoDbTestRule.java
+++ b/log4j-mongodb4/src/test/java/org/apache/logging/log4j/mongodb4/MongoDb4TestRule.java
@@ -15,7 +15,7 @@
  * limitations under the license.
  */
 
-package org.apache.logging.log4j.mongodb2;
+package org.apache.logging.log4j.mongodb4;
 
 import java.util.Objects;
 
@@ -26,7 +26,8 @@ import org.junit.runners.model.Statement;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import com.mongodb.MongoClient;
+import com.mongodb.client.MongoClient;
+import com.mongodb.client.MongoClients;
 
 import de.flapdoodle.embed.mongo.Command;
 import de.flapdoodle.embed.mongo.MongodExecutable;
@@ -43,13 +44,17 @@ import de.flapdoodle.embed.process.runtime.Network;
 
 /**
  * A JUnit test rule to manage a MongoDB embedded instance.
- * 
+ *
  * TODO Move this class to Apache Commons Testing.
  */
-public class MongoDbTestRule implements TestRule {
+public class MongoDb4TestRule implements TestRule {
 
     public enum LoggingTarget {
-        NULL, CONSOLE
+        CONSOLE, NULL;
+
+        public static LoggingTarget getLoggingTarget(final String sysPropertyName, final LoggingTarget defaultValue) {
+            return LoggingTarget.valueOf(System.getProperty(sysPropertyName, defaultValue.name()));
+        }
     }
 
     private static final int BUILDER_TIMEOUT_MILLIS = 30000;
@@ -58,48 +63,17 @@ public class MongoDbTestRule implements TestRule {
         return BUILDER_TIMEOUT_MILLIS;
     }
 
-    /**
-     * 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 final MongodStarter starter;
-
-    protected final String portSystemPropertyName;
-
-    protected MongoClient mongoClient;
-    protected MongodExecutable mongodExecutable;
-    protected MongodProcess mongodProcess;
-    protected final LoggingTarget loggingTarget;
-
-    /**
-     * Constructs a new test rule.
-     *
-     * @param portSystemPropertyName
-     *            The system property name for the MongoDB port.
-     * @param loggingTarget
-     *            The logging target
-     */
-    public MongoDbTestRule(final String portSystemPropertyName, final LoggingTarget loggingTarget) {
-        this.portSystemPropertyName = Objects.requireNonNull(portSystemPropertyName, "portSystemPropertyName");
-        this.loggingTarget = loggingTarget;
-        this.starter = getMongodStarter(loggingTarget);
-    }
-
     private static MongodStarter getMongodStarter(final LoggingTarget loggingTarget) {
         if (loggingTarget == null) {
             return MongodStarter.getDefaultInstance();
         }
         switch (loggingTarget) {
         case NULL:
-            final Logger logger = LoggerFactory.getLogger(MongoDbTestRule.class.getName());
+            final Logger logger = LoggerFactory.getLogger(MongoDb4TestRule.class.getName());
             final IRuntimeConfig runtimeConfig = new RuntimeConfigBuilder()
             // @formatter:off
-                .defaultsWithLogger(Command.MongoD, logger)
-                .processOutput(ProcessOutput.getDefaultInstanceSilent())
-                .build();
+                    .defaultsWithLogger(Command.MongoD, logger).processOutput(ProcessOutput.getDefaultInstanceSilent())
+                    .build();
             // @formatter:on
 
             return MongodStarter.getInstance(runtimeConfig);
@@ -110,6 +84,37 @@ public class MongoDbTestRule implements TestRule {
         }
     }
 
+    protected final LoggingTarget loggingTarget;
+
+    protected MongoClient mongoClient;
+    protected MongodExecutable mongodExecutable;
+    protected MongodProcess mongodProcess;
+    protected final String portSystemPropertyName;
+
+    /**
+     * 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 final MongodStarter starter;
+
+    /**
+     * Constructs a new test rule.
+     *
+     * @param portSystemPropertyName The system property name for the MongoDB port.
+     * @param clazz                  The test case class.
+     * @param defaultLoggingTarget   The logging target.
+     */
+    public MongoDb4TestRule(final String portSystemPropertyName, final Class<?> clazz,
+            final LoggingTarget defaultLoggingTarget) {
+        this.portSystemPropertyName = Objects.requireNonNull(portSystemPropertyName, "portSystemPropertyName");
+        this.loggingTarget = LoggingTarget.getLoggingTarget(clazz.getName() + "." + LoggingTarget.class.getSimpleName(),
+                defaultLoggingTarget);
+        this.starter = getMongodStarter(this.loggingTarget);
+    }
+
     @Override
     public Statement apply(final Statement base, final Description description) {
         return new Statement() {
@@ -121,15 +126,12 @@ public class MongoDbTestRule implements TestRule {
                 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());
+                        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);
+                mongoClient = MongoClients.create("mongodb://localhost:" + port);
                 try {
                     base.evaluate();
                 } finally {
@@ -164,8 +166,8 @@ public class MongoDbTestRule implements TestRule {
 
     @Override
     public String toString() {
-        StringBuilder builder = new StringBuilder();
-        builder.append("MongoDbTestRule [starter=");
+        final StringBuilder builder = new StringBuilder();
+        builder.append("Mongo4TestRule [starter=");
         builder.append(starter);
         builder.append(", portSystemPropertyName=");
         builder.append(portSystemPropertyName);
@@ -181,4 +183,4 @@ public class MongoDbTestRule implements TestRule {
         return builder.toString();
     }
 
-}
+}
\ No newline at end of file
diff --git a/log4j-mongodb2/src/test/java/org/apache/logging/log4j/mongodb2/MongoDbTestTestRuleTest.java b/log4j-mongodb4/src/test/java/org/apache/logging/log4j/mongodb4/MongoDb4TestTestRuleTest.java
similarity index 75%
rename from log4j-mongodb2/src/test/java/org/apache/logging/log4j/mongodb2/MongoDbTestTestRuleTest.java
rename to log4j-mongodb4/src/test/java/org/apache/logging/log4j/mongodb4/MongoDb4TestTestRuleTest.java
index 68e9782..086af07 100644
--- a/log4j-mongodb2/src/test/java/org/apache/logging/log4j/mongodb2/MongoDbTestTestRuleTest.java
+++ b/log4j-mongodb4/src/test/java/org/apache/logging/log4j/mongodb4/MongoDb4TestTestRuleTest.java
@@ -15,13 +15,11 @@
  * limitations under the license.
  */
 
-package org.apache.logging.log4j.mongodb2;
-
-import java.util.List;
+package org.apache.logging.log4j.mongodb4;
 
 import org.apache.commons.lang3.JavaVersion;
 import org.apache.commons.lang3.SystemUtils;
-import org.apache.logging.log4j.mongodb2.MongoDbTestRule.LoggingTarget;
+import org.apache.logging.log4j.mongodb4.MongoDb4TestRule.LoggingTarget;
 import org.apache.logging.log4j.test.AvailablePortSystemPropertyTestRule;
 import org.apache.logging.log4j.test.RuleChainFactory;
 import org.junit.Assert;
@@ -31,18 +29,21 @@ import org.junit.ClassRule;
 import org.junit.Test;
 import org.junit.rules.RuleChain;
 
+import com.mongodb.client.MongoIterable;
+
 /**
- * Tests {@link MongoDbTestRule}. This class name does NOT end in "Test" in order to only be picked up by {@link Java8Test}.
+ * Tests MongoDbRule.
  * <p>
  * The test framework {@code de.flapdoodle.embed.mongo} requires Java 8.
  * </p>
  */
-public class MongoDbTestTestRuleTest {
+public class MongoDb4TestTestRuleTest {
 
     private static final AvailablePortSystemPropertyTestRule mongoDbPortTestRule = AvailablePortSystemPropertyTestRule
-            .create(TestConstants.SYS_PROP_NAME_PORT);
+            .create(MongoDb4TestConstants.SYS_PROP_NAME_PORT);
 
-    private static final MongoDbTestRule mongoDbTestRule = new MongoDbTestRule(mongoDbPortTestRule.getName(), LoggingTarget.NULL);
+    private static final MongoDb4TestRule mongoDbTestRule = new MongoDb4TestRule(mongoDbPortTestRule.getName(),
+            MongoDb4TestTestRuleTest.class, LoggingTarget.NULL);
 
     @ClassRule
     public static RuleChain mongoDbChain = RuleChainFactory.create(mongoDbPortTestRule, mongoDbTestRule);
@@ -54,12 +55,13 @@ public class MongoDbTestTestRuleTest {
 
     @Test
     public void testAccess() {
-        final List<String> databaseNames = mongoDbTestRule.getMongoClient().getDatabaseNames();
+        @SuppressWarnings("resource")
+        final MongoIterable<String> databaseNames = mongoDbTestRule.getMongoClient().listDatabaseNames();
         Assert.assertNotNull(databaseNames);
-        Assert.assertFalse(databaseNames.isEmpty());
-        Assert.assertNotNull(databaseNames.get(0));
+        Assert.assertNotNull(databaseNames.first());
     }
 
+    @SuppressWarnings("resource")
     @Test
     public void testMongoDbTestRule() {
         Assert.assertNotNull(mongoDbTestRule);
diff --git a/log4j-mongodb2/src/test/resources/log4j2-mongodb-auth-failure.xml b/log4j-mongodb4/src/test/resources/log4j2-mongodb-auth-failure.xml
similarity index 86%
rename from log4j-mongodb2/src/test/resources/log4j2-mongodb-auth-failure.xml
rename to log4j-mongodb4/src/test/resources/log4j2-mongodb-auth-failure.xml
index 43d7e37..34be399 100644
--- a/log4j-mongodb2/src/test/resources/log4j2-mongodb-auth-failure.xml
+++ b/log4j-mongodb4/src/test/resources/log4j2-mongodb-auth-failure.xml
@@ -19,8 +19,8 @@
 <Configuration status="WARN">
   <Appenders>
     <NoSql name="MongoDbAppender">
-      <MongoDb2 databaseName="test" collectionName="applog" server="localhost" userName="log4jUser" password="12345678"
-        port="${sys:MongoDBTestPort:-27017}" />
+      <MongoDb4 
+        connection="mongodb://log4jUser:12345678@localhost:${sys:MongoDBTestPort:-27017}/testDb.testCollection" />
     </NoSql>
   </Appenders>
   <Loggers>
diff --git a/log4j-mongodb2/src/test/resources/log4j2-mongodb-capped.xml b/log4j-mongodb4/src/test/resources/log4j2-mongodb-capped.xml
similarity index 85%
rename from log4j-mongodb2/src/test/resources/log4j2-mongodb-capped.xml
rename to log4j-mongodb4/src/test/resources/log4j2-mongodb-capped.xml
index 7eda0ae..d5f5651 100644
--- a/log4j-mongodb2/src/test/resources/log4j2-mongodb-capped.xml
+++ b/log4j-mongodb4/src/test/resources/log4j2-mongodb-capped.xml
@@ -19,8 +19,10 @@
 <Configuration status="WARN">
   <Appenders>
     <NoSql name="MongoDbAppender">
-      <MongoDb2 databaseName="test" collectionName="applog" server="localhost" capped="true" collectionSize="1073741824"
-        port="${sys:MongoDBTestPort:-27017}" />
+      <MongoDb4 
+        connection="mongodb://localhost:${sys:MongoDBTestPort:-27017}/testDb.testCollection" 
+        capped="true" 
+        collectionSize="1073741824"/>
     </NoSql>
   </Appenders>
   <Loggers>
diff --git a/log4j-mongodb2/src/test/resources/log4j2-mongodb-map-message.xml b/log4j-mongodb4/src/test/resources/log4j2-mongodb-map-message.xml
similarity index 89%
rename from log4j-mongodb2/src/test/resources/log4j2-mongodb-map-message.xml
rename to log4j-mongodb4/src/test/resources/log4j2-mongodb-map-message.xml
index 12f957a..7534477 100644
--- a/log4j-mongodb2/src/test/resources/log4j2-mongodb-map-message.xml
+++ b/log4j-mongodb4/src/test/resources/log4j2-mongodb-map-message.xml
@@ -19,8 +19,7 @@
 <Configuration status="WARN">
   <Appenders>
     <NoSql name="MongoDbAppender">
-      <MongoDb2 databaseName="test" collectionName="applog" server="localhost"
-        port="${sys:MongoDBTestPort:-27017}" />
+      <MongoDb4 connection="mongodb://localhost:${sys:MongoDBTestPort:-27017}/testDb.testCollection" />
       <MessageLayout />
     </NoSql>
   </Appenders>
diff --git a/log4j-mongodb2/src/test/resources/log4j2-mongodb.xml b/log4j-mongodb4/src/test/resources/log4j2-mongodb.xml
similarity index 89%
rename from log4j-mongodb2/src/test/resources/log4j2-mongodb.xml
rename to log4j-mongodb4/src/test/resources/log4j2-mongodb.xml
index 805c746..514bc8c 100644
--- a/log4j-mongodb2/src/test/resources/log4j2-mongodb.xml
+++ b/log4j-mongodb4/src/test/resources/log4j2-mongodb.xml
@@ -19,8 +19,7 @@
 <Configuration status="WARN">
   <Appenders>
     <NoSql name="MongoDbAppender">
-      <MongoDb2 databaseName="test" collectionName="applog" server="localhost"
-        port="${sys:MongoDBTestPort:-27017}" />
+      <MongoDb4 connection="mongodb://localhost:${sys:MongoDBTestPort:-27017}/testDb.testCollection" />
     </NoSql>
   </Appenders>
   <Loggers>
diff --git a/pom.xml b/pom.xml
index c31a74d..cabbefb 100644
--- a/pom.xml
+++ b/pom.xml
@@ -193,8 +193,8 @@
     <flumeVersion>1.9.0</flumeVersion>
     <disruptorVersion>3.4.2</disruptorVersion>
     <conversantDisruptorVersion>1.2.15</conversantDisruptorVersion>
-    <mongodb2.version>2.14.3</mongodb2.version>
-    <mongodb3.version>3.10.2</mongodb3.version>
+    <mongodb3.version>3.12.4</mongodb3.version>
+    <mongodb4.version>4.0.3</mongodb4.version>
     <groovy.version>2.5.6</groovy.version>
     <compiler.plugin.version>3.8.1</compiler.plugin.version>
     <pmd.plugin.version>3.10.0</pmd.plugin.version>
@@ -774,21 +774,6 @@
         <scope>provided</scope>
       </dependency>
       <dependency>
-        <groupId>org.mongodb</groupId>
-        <artifactId>mongo-java-driver</artifactId>
-        <version>${mongodb2.version}</version>
-      </dependency>
-      <dependency>
-        <groupId>org.mongodb</groupId>
-        <artifactId>mongodb-driver</artifactId>
-        <version>${mongodb3.version}</version>
-      </dependency>
-      <dependency>
-        <groupId>org.mongodb</groupId>
-        <artifactId>bson</artifactId>
-        <version>${mongodb3.version}</version>
-      </dependency>
-      <dependency>
         <groupId>org.lightcouch</groupId>
         <artifactId>lightcouch</artifactId>
         <version>0.0.6</version>
@@ -1536,8 +1521,8 @@
     <module>log4j-jms</module>
     <module>log4j-kafka</module>
     <module>log4j-couchdb</module>
-    <module>log4j-mongodb2</module>
     <module>log4j-mongodb3</module>
+    <module>log4j-mongodb4</module>
     <module>log4j-cassandra</module>
     <module>log4j-web</module>
     <module>log4j-perf</module>
diff --git a/src/changes/changes.xml b/src/changes/changes.xml
index c227468..6a47c04 100644
--- a/src/changes/changes.xml
+++ b/src/changes/changes.xml
@@ -171,6 +171,14 @@
         Null pointer exception when no network interfaces are available.
       </action>
     </release>
+    <release version="2.14.0" date="2020-05-10" description="GA Release 2.13.3">
+      <action issue="LOG4J2-2848" dev="ggregory" type="add">
+        Create module log4j-mongodb4 to use new major version 4 MongoDB driver.
+      </action>
+      <action issue="LOG4J2-2851" dev="ggregory" type="remove">
+        Drop log4j-mongodb2 module.
+      </action>
+    </release>
     <release version="2.13.3" date="2020-05-10" description="GA Release 2.13.3">
       <action issue="LOG4J2-2838" dev="rgoers" type="fix">
         Fix NullPointerException in ThreadContextDataInjector.
diff --git a/src/site/asciidoc/javadoc.adoc b/src/site/asciidoc/javadoc.adoc
index 8a0ed75..610bd85 100644
--- a/src/site/asciidoc/javadoc.adoc
+++ b/src/site/asciidoc/javadoc.adoc
@@ -83,12 +83,12 @@ likely will not use directly in code but instead will only configure or include
 |link:log4j-liquibase/apidocs/index.html[Log4j Liquibase Binding]
 |The Apache Log4j Liquibase binding to Log4j 2 Core.
 
-|link:log4j-mongodb2/apidocs/index.html[Log4j MongoDB 2 Support]
-|Additional Appender for MongoDB using the version 2 driver.
-
 |link:log4j-mongodb3/apidocs/index.html[Log4j MongoDB 3 Support]
 |Additional Appender for MongoDB using the version 3 driver.
 
+|link:log4j-mongodb4/apidocs/index.html[Log4j MongoDB 4 Support]
+|Additional Appender for MongoDB using the version 4 driver.
+
 |link:log4j-cassandra/apidocs/index.html[Log4j Cassandra Support]
 |Additional Appender for Cassandra.
 |===
diff --git a/src/site/asciidoc/manual/appenders.adoc b/src/site/asciidoc/manual/appenders.adoc
index 430d347..9476517 100644
--- a/src/site/asciidoc/manual/appenders.adoc
+++ b/src/site/asciidoc/manual/appenders.adoc
@@ -1930,29 +1930,26 @@ databases if represented in a JSON format:
 [#NoSQLAppenderMongoDB]
 == NoSQLAppenderMongoDB
 
-Starting with Log4 2.11.0, we provide two MongoDB modules:
+We provide the following MongoDB modules:
 
-* `log4j-mongodb2` defines the configuration element
-link:#NoSQLAppenderMongoDB2[`MongoDb2`] matching the MongoDB Driver
-version 2.
-* `log4j-mongodb3` defines the configuration element
+* Added in 2.11.0: `log4j-mongodb3` defines the configuration element
 link:#NoSQLAppenderMongoDB3[`MongoDb3`] matching the MongoDB Driver
 version 3.
+* Added in 2.14.0: `log4j-mongodb4` defines the configuration element
+link:#NoSQLAppenderMongoDB4[`MongoDb4`] matching the MongoDB Driver
+version 4.
 
-We no longer provide the module `log4j-mongodb`.
+We no longer provide the modules `log4j-mongodb` and `log4j-mongodb2`.
 
-The module `log4j-mongodb2` aliases the old configuration element
-`MongoDb` to link:#NoSQLAppenderMongoDB2[`MongoDb2`].
-
-[#NoSQLAppenderMongoDB2]
-== NoSQLAppenderMongoDB2
+[#NoSQLAppenderMongoDB3]
+== NoSQLAppenderMongoDB3
 
 This section details specializations of the
 link:#NoSQLAppender[NoSQLAppender] provider for MongoDB using the
-MongoDB driver version 2. The NoSQLAppender Appender writes log events
+MongoDB driver version 3. The NoSQLAppender Appender writes log events
 to a NoSQL database using an internal lightweight provider interface.
 
-.MongoDB2 Provider Parameters
+.MongoDB3 Provider Parameters
 [cols=",,",options="header",]
 |=======================================================================
 |Parameter Name |Type |Description
@@ -1972,7 +1969,8 @@ your own custom instructions).
 |factoryClassName |Class |To provide a connection to the MongoDB
 database, you can use this attribute and `factoryMethodName` to specify
 a class and static method to get the connection from. The method must
-return a `com.mongodb.DB` or a `com.mongodb.MongoClient`. If the `DB` is
+return a `com.mongodb.client.MongoDatabase` or a
+`com.mongodb.MongoClient`. If the `com.mongodb.client.MongoDatabase` is
 not authenticated, you must also specify a `username` and `password`. If
 you use the factory method for providing a connection, you must not
 specify the `databaseName`, `server`, or `port` attributes.
@@ -2009,7 +2007,7 @@ collection documentation linked above for more information.
 
 This appender is link:messages.html#MapMessage[MapMessage]-aware.
 
-Here are a few sample configurations for the NoSQLAppender and MongoDB2
+Here are a few sample configurations for the NoSQLAppender and MongoDB3
 provider:
 
 [source,xml]
@@ -2018,7 +2016,7 @@ provider:
 <Configuration status="error">
   <Appenders>
     <NoSql name="databaseAppender">
-      <MongoDb2 databaseName="applicationDb" collectionName="applicationLog" server="mongo.example.org"
+      <MongoDb3 databaseName="applicationDb" collectionName="applicationLog" server="mongo.example.org"
                username="loggingUser" password="abc123" />
     </NoSql>
   </Appenders>
@@ -2036,7 +2034,7 @@ provider:
 <Configuration status="error">
   <Appenders>
     <NoSql name="databaseAppender">
-      <MongoDb2 collectionName="applicationLog" factoryClassName="org.example.db.ConnectionFactory"
+      <MongoDb3 collectionName="applicationLog" factoryClassName="org.example.db.ConnectionFactory"
                factoryMethodName="getNewMongoClient" />
     </NoSql>
   </Appenders>
@@ -2048,62 +2046,21 @@ provider:
 </Configuration>
 ----
 
-Starting in Log4j version 2.11.0, the provider element name is
-`MongoDb2`. The name `MongoDb` is now a deprecated alias for `MongoDb2`.
-
-[#NoSQLAppenderMongoDB3]
-== NoSQLAppenderMongoDB3
+[#NoSQLAppenderMongoDB4]
+== NoSQLAppenderMongoDB4
 
 This section details specializations of the
 link:#NoSQLAppender[NoSQLAppender] provider for MongoDB using the
-MongoDB driver version 3. The NoSQLAppender Appender writes log events
+MongoDB driver version 4. The NoSQLAppender Appender writes log events
 to a NoSQL database using an internal lightweight provider interface.
 
 .MongoDB3 Provider Parameters
 [cols=",,",options="header",]
 |=======================================================================
 |Parameter Name |Type |Description
-|collectionName |String |_Required._ The name of the MongoDB collection
-to insert the events into.
-
-|writeConcernConstant |Field |By default, the MongoDB provider inserts
-records with the instructions `com.mongodb.WriteConcern.ACKNOWLEDGED`.
-Use this optional attribute to specify the name of a constant other than
-`ACKNOWLEDGED`.
-
-|writeConcernConstantClass |Class |If you specify
-`writeConcernConstant`, you can use this attribute to specify a class
-other than `com.mongodb.WriteConcern` to find the constant on (to create
-your own custom instructions).
-
-|factoryClassName |Class |To provide a connection to the MongoDB
-database, you can use this attribute and `factoryMethodName` to specify
-a class and static method to get the connection from. The method must
-return a `com.mongodb.client.MongoDatabase` or a
-`com.mongodb.MongoClient`. If the `com.mongodb.client.MongoDatabase` is
-not authenticated, you must also specify a `username` and `password`. If
-you use the factory method for providing a connection, you must not
-specify the `databaseName`, `server`, or `port` attributes.
-
-|factoryMethodName |Method |See the documentation for attribute
-`factoryClassName`.
-
-|databaseName |String |If you do not specify a `factoryClassName` and
-`factoryMethodName` for providing a MongoDB connection, you must specify
-a MongoDB database name using this attribute. You must also specify a
-`username` and `password`. You can optionally also specify a `server`
-(defaults to localhost), and a `port` (defaults to the default MongoDB
-port).
-
-|server |String |See the documentation for attribute `databaseName`.
-
-|port |int |See the documentation for attribute `databaseName`.
-
-|username |String |See the documentation for attributes `databaseName`
-and `factoryClassName`.
-
-|password |String |See the documentation for attributes `databaseName`
-and `factoryClassName`.
+|connection |String |_Required._ The MongoDB 
+http://mongodb.github.io/mongo-java-driver/4.0/apidocs/mongodb-driver-core/com/mongodb/ConnectionString.html?is-external=true"[connection string] 
+in the format `mongodb://[username:password@]host1[:port1][,host2[:port2],...[,hostN[:portN]]][/[database.collection][?options]]`.
 
 |capped |boolean |Enable support for
 https://docs.mongodb.com/manual/core/capped-collections/[capped
@@ -2117,22 +2074,21 @@ collection documentation linked above for more information.
 
 This appender is link:messages.html#MapMessage[MapMessage]-aware.
 
-Here are a few sample configurations for the NoSQLAppender and MongoDB3
+Here are a few sample configurations for the NoSQLAppender and MongoDB4
 provider:
 
 [source,xml]
 ----
 <?xml version="1.0" encoding="UTF-8"?>
-<Configuration status="error">
+<Configuration status="WARN">
   <Appenders>
-    <NoSql name="databaseAppender">
-      <MongoDb3 databaseName="applicationDb" collectionName="applicationLog" server="mongo.example.org"
-               username="loggingUser" password="abc123" />
+    <NoSql name="MongoDbAppender">
+      <MongoDb4 connection="mongodb://log4jUser:12345678@localhost:${sys:MongoDBTestPort:-27017}/testDb.testCollection" />
     </NoSql>
   </Appenders>
   <Loggers>
-    <Root level="warn">
-      <AppenderRef ref="databaseAppender"/>
+    <Root level="ALL">
+      <AppenderRef ref="MongoDbAppender" />
     </Root>
   </Loggers>
 </Configuration>
@@ -2141,16 +2097,18 @@ provider:
 [source,xml]
 ----
 <?xml version="1.0" encoding="UTF-8"?>
-<Configuration status="error">
+<Configuration status="WARN">
   <Appenders>
-    <NoSql name="databaseAppender">
-      <MongoDb3 collectionName="applicationLog" factoryClassName="org.example.db.ConnectionFactory"
-               factoryMethodName="getNewMongoClient" />
+    <NoSql name="MongoDbAppender">
+      <MongoDb4 
+        connection="mongodb://localhost:${sys:MongoDBTestPort:-27017}/testDb.testCollection" 
+        capped="true" 
+        collectionSize="1073741824"/>
     </NoSql>
   </Appenders>
   <Loggers>
-    <Root level="warn">
-      <AppenderRef ref="databaseAppender"/>
+    <Root level="ALL">
+      <AppenderRef ref="MongoDbAppender" />
     </Root>
   </Loggers>
 </Configuration>
diff --git a/src/site/asciidoc/manual/messages.adoc b/src/site/asciidoc/manual/messages.adoc
index 8c27dc3..cf0e069 100644
--- a/src/site/asciidoc/manual/messages.adoc
+++ b/src/site/asciidoc/manual/messages.adoc
@@ -228,8 +228,8 @@ with a `MessageLayout`, it converts a Log4j `MapMessage` to a JMS
 * When a link:appenders.html#JDBCAppender[JDBC Appender] is configured
 with a `MessageLayout`, it converts a Log4j `MapMessage` to values in a
 SQL INSERT statement.
-* When a link:appenders.html#NoSQLAppenderMongoDB2[MongoDB2 Appender] or
-link:appenders.html#NoSQLAppenderMongoDB3[MongoDB3 Appender] is
+* When a link:appenders.html#NoSQLAppenderMongoDB3[MongoDB3 Appender] or
+link:appenders.html#NoSQLAppenderMongoDB4[MongoDB4 Appender] is
 configured with a `MessageLayout`, it converts a Log4j `MapMessage` to
 fields in a MongoDB object.
 
diff --git a/src/site/site.xml b/src/site/site.xml
index 4fa5a95..a89dc80 100644
--- a/src/site/site.xml
+++ b/src/site/site.xml
@@ -176,8 +176,8 @@
         <item name="Memory Mapped File" href="/manual/appenders.html#MemoryMappedFileAppender"/>
         <item name="NoSQL" href="/manual/appenders.html#NoSQLAppender"/>
         <item name="NoSQL for MongoDB" href="/manual/appenders.html#NoSQLAppenderMongoDB"/>
-        <item name="NoSQL for MongoDB 2" href="/manual/appenders.html#NoSQLAppenderMongoDB2"/>
         <item name="NoSQL for MongoDB 3" href="/manual/appenders.html#NoSQLAppenderMongoDB3"/>
+        <item name="NoSQL for MongoDB 4" href="/manual/appenders.html#NoSQLAppenderMongoDB4"/>
         <item name="NoSQL for CouchDB" href="/manual/appenders.html#NoSQLAppenderCouchDB"/>
         <item name="Output Stream" href="/manual/appenders.html#OutputStreamAppender"/>
         <item name="Random Access File" href="/manual/appenders.html#RandomAccessFileAppender"/>
@@ -316,8 +316,8 @@
       <item name="Log4j Web Application Support" href="log4j-web/index.html"/>
       <item name="Log4j Application Server Integration" href="log4j-appserver/index.html"/>
       <item name="Log4j CouchDB appender" href="log4j-couchdb/index.html"/>
-      <item name="Log4j MongoDB2 appender" href="log4j-mongodb2/index.html"/>
       <item name="Log4j MongoDB3 appender" href="log4j-mongodb3/index.html"/>
+      <item name="Log4j MongoDB4 appender" href="log4j-mongodb4/index.html"/>
       <item name="Log4j Cassandra appender" href="log4j-cassandra/index.html"/>
       <item name="Log4j IO Streams" href="log4j-iostreams/index.html"/>
       <item name="Log4j Liquibase Binding" href="log4j-liquibase/index.html"/>