You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tinkerpop.apache.org by sp...@apache.org on 2021/06/11 22:52:25 UTC

[tinkerpop] 01/01: TINKERPOP-2534 wip

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

spmallette pushed a commit to branch TINKERPOP-2534
in repository https://gitbox.apache.org/repos/asf/tinkerpop.git

commit 844efbef707eff5976e9b4548dff7c0f021afb3a
Author: Stephen Mallette <st...@amazon.com>
AuthorDate: Fri Jun 11 18:51:45 2021 -0400

    TINKERPOP-2534 wip
---
 docker/gremlin-server/docker-entrypoint.sh         |   2 +-
 docs/src/dev/developer/for-committers.asciidoc     |   6 +-
 docs/src/reference/gremlin-applications.asciidoc   |   2 +-
 .../src/main/resources/archetype-resources/pom.xml |   6 +-
 .../resources/archetype-resources/README.asciidoc  |   2 +-
 .../archetype-resources/conf/log4j-test.properties |  21 ---
 .../archetype-resources/conf/log4j.properties      |  21 ---
 .../archetype-resources/conf/logback-test.xml      |  26 +++
 .../resources/archetype-resources/conf/logback.xml |  26 +++
 .../src/main/resources/archetype-resources/pom.xml |   8 +-
 .../src/main/resources/archetype-resources/pom.xml |   6 +-
 gremlin-console/conf/log4j-console.properties      |  29 ----
 gremlin-console/conf/logback.xml                   |  33 ++++
 gremlin-console/pom.xml                            |   9 +-
 gremlin-console/src/main/bin/gremlin.sh            |   4 +-
 gremlin-console/src/main/static/LICENSE            |   6 +-
 gremlin-console/src/main/static/licenses/logback   |  14 ++
 .../src/test/resources/log4j-silent.properties     |  23 ---
 .../src/test/resources/log4j-test.properties       |  21 ---
 .../src/test/resources/logback-silent.xml          |  26 +++
 .../src/test/resources/logback-test.xml            |  26 +++
 gremlin-core/pom.xml                               |   4 +-
 .../EdgeLabelVerificationStrategyTest.java         |  76 +++------
 .../ReservedKeysVerificationStrategyTest.java      |  78 +++------
 .../src/test/resources/log4j-silent.properties     |  27 ---
 .../src/test/resources/log4j-test.properties       |  25 ---
 gremlin-core/src/test/resources/logback-silent.xml |  29 ++++
 gremlin-core/src/test/resources/logback-test.xml   |  28 ++++
 gremlin-dotnet/src/pom.xml                         |   6 +-
 gremlin-dotnet/test/pom.xml                        |   6 +-
 gremlin-driver/pom.xml                             |  17 +-
 gremlin-driver/src/main/bin/config-eval.sh         |   2 +-
 gremlin-driver/src/main/bin/profile-driver.sh      |   2 +-
 .../src/main/conf/log4j-driver.properties          |  25 ---
 gremlin-driver/src/main/conf/logback.xml           |  28 ++++
 gremlin-driver/src/main/static/LICENSE             |  12 +-
 gremlin-driver/src/main/static/licenses/logback    |  14 ++
 gremlin-driver/src/main/static/licenses/slf4j      |  21 +++
 .../tinkerpop/gremlin/driver/ClientTest.java       |   2 +
 .../WebSocketClientBehaviorIntegrateTest.java      |  59 +++----
 .../ser/GraphSONMessageSerializerV2d0Test.java     |  14 +-
 .../ser/GraphSONMessageSerializerV3d0Test.java     |  15 +-
 .../gremlin/util/Log4jRecordingAppender.java       |  86 ----------
 .../gremlin/util/Log4jRecordingAppenderTest.java   |  86 ----------
 .../src/test/resources/log4j-silent.properties     |  23 ---
 .../src/test/resources/log4j-test.properties       |  21 ---
 .../src/test/resources/logback-silent.xml          |  26 +++
 gremlin-driver/src/test/resources/logback-test.xml |  26 +++
 gremlin-groovy/pom.xml                             |   4 +-
 .../src/test/resources/log4j-silent.properties     |  23 ---
 .../src/test/resources/log4j-test.properties       |  21 ---
 .../src/test/resources/logback-silent.xml          |  26 +++
 gremlin-groovy/src/test/resources/logback-test.xml |  26 +++
 gremlin-javascript/pom.xml                         |   6 +-
 .../javascript/gremlin-javascript/package.json     |   2 +-
 gremlin-python/pom.xml                             |   6 +-
 gremlin-server/conf/log4j-server.properties        |  32 ----
 gremlin-server/conf/logback.xml                    |  20 +++
 gremlin-server/pom.xml                             |  14 +-
 gremlin-server/src/main/bin/gremlin-server.bat     |   4 +-
 gremlin-server/src/main/bin/gremlin-server.sh      |  12 +-
 .../tinkerpop/gremlin/server/GremlinServer.java    |   2 +-
 gremlin-server/src/main/static/LICENSE             |   6 +-
 gremlin-server/src/main/static/licenses/logback    |  14 ++
 .../driver/ClientConnectionIntegrateTest.java      |  53 +++---
 .../tinkerpop/gremlin/server/ContextTest.java      |  63 +++----
 .../gremlin/server/GremlinDriverIntegrateTest.java |  45 ++---
 ...emlinServerAuditLogDeprecatedIntegrateTest.java | 181 ++++++++++-----------
 .../server/GremlinServerAuditLogIntegrateTest.java | 180 +++++++++-----------
 .../server/GremlinServerAuthKrb5IntegrateTest.java |  12 --
 .../server/GremlinServerAuthzIntegrateTest.java    |  49 +++---
 .../gremlin/server/GremlinServerIntegrateTest.java |  49 +++---
 .../server/GremlinServerSessionIntegrateTest.java  |  46 ++++--
 .../gremlin/util/Log4jRecordingAppender.java       |  85 ----------
 .../gremlin/util/Log4jRecordingAppenderTest.java   |  86 ----------
 .../src/test/resources/log4j-silent.properties     |  23 ---
 .../src/test/resources/log4j-test.properties       |  28 ----
 .../src/test/resources/logback-silent.xml          |  27 +++
 gremlin-server/src/test/resources/logback-test.xml |  36 ++++
 gremlin-test/pom.xml                               |   8 +-
 .../src/test/resources/log4j-silent.properties     |  29 ----
 .../src/test/resources/log4j-test.properties       |  27 ---
 gremlin-test/src/test/resources/logback-silent.xml |  28 ++++
 gremlin-test/src/test/resources/logback-test.xml   |  28 ++++
 gremlin-tools/gremlin-benchmark/pom.xml            |  11 +-
 .../src/test/resources/log4j-silent.properties     |  23 ---
 .../src/test/resources/log4j-test.properties       |  21 ---
 .../src/test/resources/logback-silent.xml          |  26 +++
 .../src/test/resources/logback-test.xml            |  26 +++
 gremlin-tools/gremlin-coverage/pom.xml             |   5 +-
 gremlin-tools/gremlin-io-test/pom.xml              |  11 +-
 .../src/test/resources/log4j-silent.properties     |  23 ---
 .../src/test/resources/log4j-test.properties       |  21 ---
 .../src/test/resources/logback-silent.xml          |  26 +++
 .../src/test/resources/logback-test.xml            |  26 +++
 hadoop-gremlin/pom.xml                             |  22 ++-
 .../src/test/resources/log4j-silent.properties     |  26 ---
 .../src/test/resources/log4j-test.properties       |  24 ---
 .../src/test/resources/logback-silent.xml          |  28 ++++
 hadoop-gremlin/src/test/resources/logback-test.xml |  28 ++++
 neo4j-gremlin/pom.xml                              |   4 +-
 .../src/test/resources/log4j-silent.properties     |  26 ---
 .../src/test/resources/log4j-test.properties       |  24 ---
 .../src/test/resources/logback-silent.xml          |  28 ++++
 neo4j-gremlin/src/test/resources/logback-test.xml  |  28 ++++
 pom.xml                                            |  46 ++++--
 spark-gremlin/pom.xml                              |  16 +-
 .../src/test/resources/log4j-silent.properties     |  26 ---
 .../src/test/resources/log4j-test.properties       |  28 ----
 .../src/test/resources/logback-silent.xml          |  28 ++++
 spark-gremlin/src/test/resources/logback-test.xml  |  30 ++++
 sparql-gremlin/pom.xml                             |   4 +-
 .../src/test/resources/log4j-silent.properties     |  23 ---
 .../src/test/resources/log4j-test.properties       |  23 ---
 .../src/test/resources/logback-silent.xml          |  26 +++
 sparql-gremlin/src/test/resources/logback-test.xml |  26 +++
 tinkergraph-gremlin/pom.xml                        |   4 +-
 .../src/test/resources/log4j-silent.properties     |  26 ---
 .../src/test/resources/log4j-test.properties       |  24 ---
 .../src/test/resources/logback-silent.xml          |  28 ++++
 .../src/test/resources/logback-test.xml            |  28 ++++
 121 files changed, 1475 insertions(+), 1744 deletions(-)

diff --git a/docker/gremlin-server/docker-entrypoint.sh b/docker/gremlin-server/docker-entrypoint.sh
index 7031cec..90490b3 100644
--- a/docker/gremlin-server/docker-entrypoint.sh
+++ b/docker/gremlin-server/docker-entrypoint.sh
@@ -43,7 +43,7 @@ java -version
 /opt/gremlin-server/bin/gremlin-server.sh conf/gremlin-server-integration-secure.yaml &
 
 java -cp /opt/gremlin-test/gremlin-test-${GREMLIN_SERVER_VERSION}-jar-with-dependencies.jar \
-     -Dlog4j.configuration="file:/opt/gremlin-server/conf/log4j-server.properties" \
+     -Dlogback.configurationFile="file:/opt/gremlin-server/conf/logback.xml" \
      org.apache.tinkerpop.gremlin.server.KdcFixture /opt/gremlin-server &
 
 export JAVA_OPTIONS="-Xms512m -Xmx4096m -Djava.security.krb5.conf=/opt/gremlin-server/target/kdc/krb5.conf"
diff --git a/docs/src/dev/developer/for-committers.asciidoc b/docs/src/dev/developer/for-committers.asciidoc
index 6abcd0f..dda05e0 100644
--- a/docs/src/dev/developer/for-committers.asciidoc
+++ b/docs/src/dev/developer/for-committers.asciidoc
@@ -790,10 +790,10 @@ only happen from that branch.
 [[logging]]
 == Logging
 
-TinkerPop uses SLF4j for logging and typically leans back on Log4j as the implementation. Configuring log outputs
-for debugging purposes within tests can be altered by editing the `log4j-test.properties` file in each module's test
+TinkerPop uses SLF4j for logging and relies on logback as the implementation. Configuring log outputs
+for debugging purposes within tests can be altered by editing the `logback-test.xml` file in each module's test
 resources.  That file gets copied to the `target/test-classes` on build and surefire and failsafe plugins in maven
-are then configured to point at that area of the file system for those configuration files. The properties files
+are then configured to point at that area of the file system for those configuration files. The XML files
 can be edited to fine tune control of the log output, but generally speaking the current configuration is likely
 best for everyone's general purposes, so if changes are made please revert them prior to commit.
 
diff --git a/docs/src/reference/gremlin-applications.asciidoc b/docs/src/reference/gremlin-applications.asciidoc
index 29a568b..e4d056b 100644
--- a/docs/src/reference/gremlin-applications.asciidoc
+++ b/docs/src/reference/gremlin-applications.asciidoc
@@ -969,7 +969,7 @@ The following table describes the various YAML configuration options that Gremli
 |authorization.authorizer |The fully qualified classname of an `Authorizer` implementation to use. |_none_
 |authorization.config |A `Map` of configuration settings to be passed to the `Authorizer` when it is constructed.  The settings available are dependent on the implementation. |_none_
 |channelizer |The fully qualified classname of the `Channelizer` implementation to use.  A `Channelizer` is a "channel initializer" which Gremlin Server uses to define the type of processing pipeline to use.  By allowing different `Channelizer` implementations, Gremlin Server can support different communication protocols (e.g. WebSocket). |`WebSocketChannelizer`
-|enableAuditLog |The `AuthenticationHandler`, `AuthorizationHandler` and processors can issue audit logging messages with the authenticated user, remote socket address and requests with a gremlin query. For privacy reasons, the default value of this setting is false. The audit logging messages are logged at the INFO level via the `audit.org.apache.tinkerpop.gremlin.server` logger, which can be configured using the log4j.properties file. |_false_
+|enableAuditLog |The `AuthenticationHandler`, `AuthorizationHandler` and processors can issue audit logging messages with the authenticated user, remote socket address and requests with a gremlin query. For privacy reasons, the default value of this setting is false. The audit logging messages are logged at the INFO level via the `audit.org.apache.tinkerpop.gremlin.server` logger, which can be configured using the `logback.xml` file. |_false_
 |graphManager |The fully qualified classname of the `GraphManager` implementation to use.  A `GraphManager` is a class that adheres to the TinkerPop `GraphManager` interface, allowing custom implementations for storing and managing graph references, as well as defining custom methods to open and close graphs instantiations. To prevent Gremlin Server from starting when all graphs fails, the `CheckedGraphManager` can be used.|`DefaultGraphManager`
 |graphs |A `Map` of `Graph` configuration files where the key of the `Map` becomes the name to which the `Graph` will be bound and the value is the file name of a `Graph` configuration file. |_none_
 |gremlinPool |The number of "Gremlin" threads available to execute actual scripts in a `ScriptEngine`. This pool represents the workers available to handle blocking operations in Gremlin Server. When set to `0`, Gremlin Server will use the value provided by `Runtime.availableProcessors()`. |0
diff --git a/gremlin-archetype/gremlin-archetype-dsl/src/main/resources/archetype-resources/pom.xml b/gremlin-archetype/gremlin-archetype-dsl/src/main/resources/archetype-resources/pom.xml
index 282779f..99a449c 100644
--- a/gremlin-archetype/gremlin-archetype-dsl/src/main/resources/archetype-resources/pom.xml
+++ b/gremlin-archetype/gremlin-archetype-dsl/src/main/resources/archetype-resources/pom.xml
@@ -35,9 +35,9 @@ limitations under the License.
             <version>${project.version}</version>
         </dependency>
         <dependency>
-            <groupId>org.slf4j</groupId>
-            <artifactId>slf4j-log4j12</artifactId>
-            <version>${slf4j.version}</version>
+            <groupId>ch.qos.logback</groupId>
+            <artifactId>logback-classic</artifactId>
+            <version>${logback.version}</version>
         </dependency>
         <dependency>
             <groupId>junit</groupId>
diff --git a/gremlin-archetype/gremlin-archetype-server/src/main/resources/archetype-resources/README.asciidoc b/gremlin-archetype/gremlin-archetype-server/src/main/resources/archetype-resources/README.asciidoc
index 9daafb2..14d6373 100644
--- a/gremlin-archetype/gremlin-archetype-server/src/main/resources/archetype-resources/README.asciidoc
+++ b/gremlin-archetype/gremlin-archetype-server/src/main/resources/archetype-resources/README.asciidoc
@@ -65,4 +65,4 @@ $ bin/gremlin-server.sh  conf/gremlin-server-modern.yaml
 Run this project as follows:
 
 [source,text]
-mvn exec:java -Dexec.mainClass="${package}.App" -Dlog4j.configuration=file:conf/log4j.properties -Dport=8182
+mvn exec:java -Dexec.mainClass="${package}.App" -Dlogback.configurationFile=file:conf/logback.xml -Dport=8182
diff --git a/gremlin-archetype/gremlin-archetype-server/src/main/resources/archetype-resources/conf/log4j-test.properties b/gremlin-archetype/gremlin-archetype-server/src/main/resources/archetype-resources/conf/log4j-test.properties
deleted file mode 100644
index ef436fe..0000000
--- a/gremlin-archetype/gremlin-archetype-server/src/main/resources/archetype-resources/conf/log4j-test.properties
+++ /dev/null
@@ -1,21 +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.
-
-log4j.rootLogger=WARN, stdout
-log4j.appender.stdout=org.apache.log4j.ConsoleAppender
-log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
-log4j.appender.stdout.layout.ConversionPattern=[%p] %C - %m%n
\ No newline at end of file
diff --git a/gremlin-archetype/gremlin-archetype-server/src/main/resources/archetype-resources/conf/log4j.properties b/gremlin-archetype/gremlin-archetype-server/src/main/resources/archetype-resources/conf/log4j.properties
deleted file mode 100644
index 2b58359..0000000
--- a/gremlin-archetype/gremlin-archetype-server/src/main/resources/archetype-resources/conf/log4j.properties
+++ /dev/null
@@ -1,21 +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.
-
-log4j.rootLogger=INFO, stdout
-log4j.appender.stdout=org.apache.log4j.ConsoleAppender
-log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
-log4j.appender.stdout.layout.ConversionPattern=[%p] %C - %m%n
\ No newline at end of file
diff --git a/gremlin-archetype/gremlin-archetype-server/src/main/resources/archetype-resources/conf/logback-test.xml b/gremlin-archetype/gremlin-archetype-server/src/main/resources/archetype-resources/conf/logback-test.xml
new file mode 100644
index 0000000..5d94c3b
--- /dev/null
+++ b/gremlin-archetype/gremlin-archetype-server/src/main/resources/archetype-resources/conf/logback-test.xml
@@ -0,0 +1,26 @@
+<!--
+Licensed to the Apache Software Foundation (ASF) under one or more
+contributor license agreements.  See the NOTICE file distributed with
+this work for additional information regarding copyright ownership.
+The ASF licenses this file to You under the Apache License, Version 2.0
+(the "License"); you may not use this file except in compliance with
+the License.  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+-->
+<configuration>
+    <appender name="stdout" class="ch.qos.logback.core.ConsoleAppender">
+        <encoder>
+            <pattern>[%p] %C - %m%n</pattern>
+        </encoder>
+    </appender>
+    <root level="WARN">
+        <appender-ref ref="stdout"/>
+    </root>
+</configuration>
\ No newline at end of file
diff --git a/gremlin-archetype/gremlin-archetype-server/src/main/resources/archetype-resources/conf/logback.xml b/gremlin-archetype/gremlin-archetype-server/src/main/resources/archetype-resources/conf/logback.xml
new file mode 100644
index 0000000..8d11ce4
--- /dev/null
+++ b/gremlin-archetype/gremlin-archetype-server/src/main/resources/archetype-resources/conf/logback.xml
@@ -0,0 +1,26 @@
+<!--
+Licensed to the Apache Software Foundation (ASF) under one or more
+contributor license agreements.  See the NOTICE file distributed with
+this work for additional information regarding copyright ownership.
+The ASF licenses this file to You under the Apache License, Version 2.0
+(the "License"); you may not use this file except in compliance with
+the License.  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+-->
+<configuration>
+    <appender name="stdout" class="ch.qos.logback.core.ConsoleAppender">
+        <encoder>
+            <pattern>[%p] %C - %m%n</pattern>
+        </encoder>
+    </appender>
+    <root level="INFO">
+        <appender-ref ref="stdout"/>
+    </root>
+</configuration>
\ No newline at end of file
diff --git a/gremlin-archetype/gremlin-archetype-server/src/main/resources/archetype-resources/pom.xml b/gremlin-archetype/gremlin-archetype-server/src/main/resources/archetype-resources/pom.xml
index 3f4945b..22ceff8 100644
--- a/gremlin-archetype/gremlin-archetype-server/src/main/resources/archetype-resources/pom.xml
+++ b/gremlin-archetype/gremlin-archetype-server/src/main/resources/archetype-resources/pom.xml
@@ -35,9 +35,9 @@ limitations under the License.
             <version>${project.version}</version>
         </dependency>
         <dependency>
-            <groupId>org.slf4j</groupId>
-            <artifactId>slf4j-log4j12</artifactId>
-            <version>${slf4j.version}</version>
+            <groupId>ch.qos.logback</groupId>
+            <artifactId>logback-classic</artifactId>
+            <version>${logback.version}</version>
         </dependency>
         <dependency>
             <groupId>org.apache.tinkerpop</groupId>
@@ -72,7 +72,7 @@ limitations under the License.
                 <version>2.22.0</version>
                 <configuration>
                     <systemPropertyVariables>
-                        <log4j.configuration>file:conf/log4j-test.properties</log4j.configuration>
+                        <logback.configurationFile>file:conf/logback-test.properties</logback.configurationFile>
                     </systemPropertyVariables>
                 </configuration>
             </plugin>
diff --git a/gremlin-archetype/gremlin-archetype-tinkergraph/src/main/resources/archetype-resources/pom.xml b/gremlin-archetype/gremlin-archetype-tinkergraph/src/main/resources/archetype-resources/pom.xml
index 6f1ebed..830e194 100644
--- a/gremlin-archetype/gremlin-archetype-tinkergraph/src/main/resources/archetype-resources/pom.xml
+++ b/gremlin-archetype/gremlin-archetype-tinkergraph/src/main/resources/archetype-resources/pom.xml
@@ -35,9 +35,9 @@ limitations under the License.
             <version>${project.version}</version>
         </dependency>
         <dependency>
-            <groupId>org.slf4j</groupId>
-            <artifactId>slf4j-log4j12</artifactId>
-            <version>${slf4j.version}</version>
+            <groupId>ch.qos.logback</groupId>
+            <artifactId>logback-classic</artifactId>
+            <version>${logback.version}</version>
         </dependency>
         <dependency>
             <groupId>junit</groupId>
diff --git a/gremlin-console/conf/log4j-console.properties b/gremlin-console/conf/log4j-console.properties
deleted file mode 100644
index f0710f6..0000000
--- a/gremlin-console/conf/log4j-console.properties
+++ /dev/null
@@ -1,29 +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.
-
-log4j.rootLogger=${gremlin.log4j.level}, stdout
-log4j.appender.stdout=org.apache.log4j.ConsoleAppender
-log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
-log4j.appender.stdout.layout.ConversionPattern=%-5p %c %x - %m%n
-
-log4j.logger.org.apache.hadoop.mapred.JobClient=INFO
-log4j.logger.org.apache.hadoop.mapreduce.Job=INFO
-log4j.logger.org.apache.tinkerpop.gremlin.driver.Host=ERROR
-log4j.logger.org.apache.tinkerpop.gremlin.hadoop.process.computer.mapreduce.MapReduceGraphComputer=INFO
-log4j.logger.org.apache.tinkerpop.gremlin.hadoop.structure.HadoopGraph=INFO
-log4j.logger.org.apache.tinkerpop.gremlin.spark.process.computer.SparkGraphComputer=INFO
-log4j.logger.org.apache.spark.metrics.MetricsSystem=ERROR
\ No newline at end of file
diff --git a/gremlin-console/conf/logback.xml b/gremlin-console/conf/logback.xml
new file mode 100644
index 0000000..b05303c
--- /dev/null
+++ b/gremlin-console/conf/logback.xml
@@ -0,0 +1,33 @@
+<!--
+Licensed to the Apache Software Foundation (ASF) under one or more
+contributor license agreements.  See the NOTICE file distributed with
+this work for additional information regarding copyright ownership.
+The ASF licenses this file to You under the Apache License, Version 2.0
+(the "License"); you may not use this file except in compliance with
+the License.  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+-->
+<configuration>
+    <appender name="stdout" class="ch.qos.logback.core.ConsoleAppender">
+        <encoder>
+            <pattern>%-5p %c %x - %m%n</pattern>
+        </encoder>
+    </appender>
+    <logger name="org.apache.tinkerpop.gremlin.hadoop.structure.HadoopGraph" level="INFO"/>
+    <logger name="org.apache.tinkerpop.gremlin.driver.Host" level="ERROR"/>
+    <logger name="org.apache.tinkerpop.gremlin.hadoop.process.computer.mapreduce.MapReduceGraphComputer" level="INFO"/>
+    <logger name="org.apache.hadoop.mapreduce.Job" level="INFO"/>
+    <logger name="org.apache.spark.metrics.MetricsSystem" level="ERROR"/>
+    <logger name="org.apache.tinkerpop.gremlin.spark.process.computer.SparkGraphComputer" level="INFO"/>
+    <logger name="org.apache.hadoop.mapred.JobClient" level="INFO"/>
+    <root level="${gremlin.logback.level}">
+        <appender-ref ref="stdout"/>
+    </root>
+</configuration>
\ No newline at end of file
diff --git a/gremlin-console/pom.xml b/gremlin-console/pom.xml
index 1e532e6..c7bd663 100644
--- a/gremlin-console/pom.xml
+++ b/gremlin-console/pom.xml
@@ -51,13 +51,8 @@ limitations under the License.
             <version>${project.version}</version>
         </dependency>
         <dependency>
-            <groupId>org.slf4j</groupId>
-            <artifactId>slf4j-log4j12</artifactId>
-            <optional>true</optional>
-        </dependency>
-        <dependency>
-            <groupId>log4j</groupId>
-            <artifactId>log4j</artifactId>
+            <groupId>ch.qos.logback</groupId>
+            <artifactId>logback-classic</artifactId>
             <optional>true</optional>
         </dependency>
         <!-- TESTING -->
diff --git a/gremlin-console/src/main/bin/gremlin.sh b/gremlin-console/src/main/bin/gremlin.sh
index bd5b71c..9fbd8a0 100755
--- a/gremlin-console/src/main/bin/gremlin.sh
+++ b/gremlin-console/src/main/bin/gremlin.sh
@@ -67,7 +67,7 @@ else
     JAVA="$JAVA_HOME/bin/java -server"
 fi
 
-# Set default message threshold for Log4j Gremlin's console appender
+# Set default message threshold for logging in Gremlin's console appender
 if [ -z "${GREMLIN_LOG_LEVEL:-}" ]; then
     GREMLIN_LOG_LEVEL=WARN
 fi
@@ -97,7 +97,7 @@ if [ ! -z "${JAVA_OPTIONS}" ]; then
     JVM_OPTS+=( "${JAVA_OPTIONS}" )
 fi
 
-JVM_OPTS+=( "-Duser.working_dir=${USER_DIR}" "-Dtinkerpop.ext=${USER_EXT_DIR:-${SYSTEM_EXT_DIR}}" "-Dlog4j.configuration=conf/log4j-console.properties" "-Dgremlin.log4j.level=$GREMLIN_LOG_LEVEL" )
+JVM_OPTS+=( "-Duser.working_dir=${USER_DIR}" "-Dtinkerpop.ext=${USER_EXT_DIR:-${SYSTEM_EXT_DIR}}" "-Dlogback.configurationFile=conf/logback.xml" "-Dgremlin.logback.level=$GREMLIN_LOG_LEVEL" )
 JVM_OPTS=$(awk -v RS=' ' '!/^$/ {if (!x[$0]++) print}' <<< "${JVM_OPTS}" | grep -v '^$' | paste -sd ' ' -)
 
 if [ -n "$SCRIPT_DEBUG" ]; then
diff --git a/gremlin-console/src/main/static/LICENSE b/gremlin-console/src/main/static/LICENSE
index f3da4f7..fa7879f 100644
--- a/gremlin-console/src/main/static/LICENSE
+++ b/gremlin-console/src/main/static/LICENSE
@@ -225,7 +225,6 @@ The Apache TinkerPop project bundles the following components under the MIT Lice
 
      JCL 1.1.1 implemented over SLF4J (org.slf4j:jcl-over-slf4j:1.7.25 - http://www.slf4j.org) - for details, see licenses/slf4j
      SLF4J API Module (org.slf4j:slf4j-api:1.7.25 - http://www.slf4j.org) - for details, see licenses/slf4j
-     SLF4J LOG4J-12 Binding (org.slf4j:slf4j-log4j12:1.7.25 - http://www.slf4j.org) - for details, see licenses/slf4j
      Foundation stylesheet for CodeRay (http://foundation.zurb.com) - for details, see licenses/foundation
      normalize.css 2.1.2 (http://necolas.github.io/normalize.css/) - for details, see licenses/normalize
 
@@ -236,3 +235,8 @@ Other Licenses
 The Apache TinkerPop project bundles the following components under the ISC License:
 
      jBCrypt (org.mindrot:jbcrypt:0.4 - https://github.com/djmdjm/jBCrypt) - for details, see licenses/jbcrypt
+
+The Apache TinkerPop project bundles the following components under the Eclipse Public License 1.0:
+
+     logback-core (ch.qos.logback:logback-core:1.2.3 - https://logback.qos.ch) - for details, see licenses/logback
+     logback-classic (ch.qos.logback:logback-classic:1.2.3 - https://logback.qos.ch) - for details, see licenses/logback
diff --git a/gremlin-console/src/main/static/licenses/logback b/gremlin-console/src/main/static/licenses/logback
new file mode 100644
index 0000000..8953762
--- /dev/null
+++ b/gremlin-console/src/main/static/licenses/logback
@@ -0,0 +1,14 @@
+Logback LICENSE
+---------------
+
+Logback: the reliable, generic, fast and flexible logging framework.
+Copyright (C) 1999-2015, QOS.ch. All rights reserved.
+
+This program and the accompanying materials are dual-licensed under
+either the terms of the Eclipse Public License v1.0 as published by
+the Eclipse Foundation
+
+  or (per the licensee's choosing)
+
+under the terms of the GNU Lesser General Public License version 2.1
+as published by the Free Software Foundation.
\ No newline at end of file
diff --git a/gremlin-console/src/test/resources/log4j-silent.properties b/gremlin-console/src/test/resources/log4j-silent.properties
deleted file mode 100644
index 1825bb0..0000000
--- a/gremlin-console/src/test/resources/log4j-silent.properties
+++ /dev/null
@@ -1,23 +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.
-
-# this file should always have logging set to OFF.  it seems, however, that an appender of some sort is
-# required or else some logs throw error and use other log4j.properties files on the path.
-log4j.rootLogger=OFF, stdout
-log4j.appender.stdout=org.apache.log4j.ConsoleAppender
-log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
-log4j.appender.stdout.layout.ConversionPattern=[%p] %C - %m%n
\ No newline at end of file
diff --git a/gremlin-console/src/test/resources/log4j-test.properties b/gremlin-console/src/test/resources/log4j-test.properties
deleted file mode 100644
index ef436fe..0000000
--- a/gremlin-console/src/test/resources/log4j-test.properties
+++ /dev/null
@@ -1,21 +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.
-
-log4j.rootLogger=WARN, stdout
-log4j.appender.stdout=org.apache.log4j.ConsoleAppender
-log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
-log4j.appender.stdout.layout.ConversionPattern=[%p] %C - %m%n
\ No newline at end of file
diff --git a/gremlin-console/src/test/resources/logback-silent.xml b/gremlin-console/src/test/resources/logback-silent.xml
new file mode 100644
index 0000000..4c5947d
--- /dev/null
+++ b/gremlin-console/src/test/resources/logback-silent.xml
@@ -0,0 +1,26 @@
+<!--
+Licensed to the Apache Software Foundation (ASF) under one or more
+contributor license agreements.  See the NOTICE file distributed with
+this work for additional information regarding copyright ownership.
+The ASF licenses this file to You under the Apache License, Version 2.0
+(the "License"); you may not use this file except in compliance with
+the License.  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+-->
+<configuration>
+    <appender name="stdout" class="ch.qos.logback.core.ConsoleAppender">
+        <encoder>
+            <pattern>[%p] %C - %m%n</pattern>
+        </encoder>
+    </appender>
+    <root level="OFF">
+        <appender-ref ref="stdout"/>
+    </root>
+</configuration>
\ No newline at end of file
diff --git a/gremlin-console/src/test/resources/logback-test.xml b/gremlin-console/src/test/resources/logback-test.xml
new file mode 100644
index 0000000..5d94c3b
--- /dev/null
+++ b/gremlin-console/src/test/resources/logback-test.xml
@@ -0,0 +1,26 @@
+<!--
+Licensed to the Apache Software Foundation (ASF) under one or more
+contributor license agreements.  See the NOTICE file distributed with
+this work for additional information regarding copyright ownership.
+The ASF licenses this file to You under the Apache License, Version 2.0
+(the "License"); you may not use this file except in compliance with
+the License.  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+-->
+<configuration>
+    <appender name="stdout" class="ch.qos.logback.core.ConsoleAppender">
+        <encoder>
+            <pattern>[%p] %C - %m%n</pattern>
+        </encoder>
+    </appender>
+    <root level="WARN">
+        <appender-ref ref="stdout"/>
+    </root>
+</configuration>
\ No newline at end of file
diff --git a/gremlin-core/pom.xml b/gremlin-core/pom.xml
index 637420f..861ef74 100644
--- a/gremlin-core/pom.xml
+++ b/gremlin-core/pom.xml
@@ -102,8 +102,8 @@ limitations under the License.
             <scope>test</scope>
         </dependency>
         <dependency>
-            <groupId>org.slf4j</groupId>
-            <artifactId>slf4j-log4j12</artifactId>
+            <groupId>io.github.hakky54</groupId>
+            <artifactId>logcaptor</artifactId>
             <scope>test</scope>
         </dependency>
         <dependency>
diff --git a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/verification/EdgeLabelVerificationStrategyTest.java b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/verification/EdgeLabelVerificationStrategyTest.java
index 1b869a4..1e9d52f 100644
--- a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/verification/EdgeLabelVerificationStrategyTest.java
+++ b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/verification/EdgeLabelVerificationStrategyTest.java
@@ -18,9 +18,7 @@
  */
 package org.apache.tinkerpop.gremlin.process.traversal.strategy.verification;
 
-import org.apache.log4j.AppenderSkeleton;
-import org.apache.log4j.Level;
-import org.apache.log4j.Logger;
+import nl.altindag.log.LogCaptor;
 import org.apache.tinkerpop.gremlin.process.traversal.Translator;
 import org.apache.tinkerpop.gremlin.process.traversal.Traversal;
 import org.apache.tinkerpop.gremlin.process.traversal.TraversalStrategies;
@@ -28,20 +26,19 @@ import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__;
 import org.apache.tinkerpop.gremlin.process.traversal.translator.GroovyTranslator;
 import org.apache.tinkerpop.gremlin.process.traversal.util.DefaultTraversalStrategies;
 import org.apache.tinkerpop.gremlin.structure.Direction;
-import org.junit.After;
+import org.junit.AfterClass;
 import org.junit.Before;
+import org.junit.BeforeClass;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
 
-import java.util.ArrayList;
 import java.util.Arrays;
-import java.util.List;
 import java.util.function.Predicate;
 import java.util.regex.Pattern;
-import java.util.stream.Stream;
 
 import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.fail;
 
 /**
@@ -55,22 +52,21 @@ public class EdgeLabelVerificationStrategyTest {
             "^The provided traversal contains a vertex step without any specified edge label: VertexStep.*")
             .asPredicate();
 
-    private TestLogAppender logAppender;
-    private Level previousLogLevel;
+    private static LogCaptor logCaptor;
+
+    @BeforeClass
+    public static void setupLogCaptor() {
+        logCaptor = LogCaptor.forClass(AbstractWarningVerificationStrategy.class);
+    }
 
     @Before
-    public void setupForEachTest() {
-        final org.apache.log4j.Logger strategyLogger = org.apache.log4j.Logger.getLogger(AbstractWarningVerificationStrategy.class);
-        previousLogLevel = strategyLogger.getLevel();
-        strategyLogger.setLevel(Level.WARN);
-        Logger.getRootLogger().addAppender(logAppender = new TestLogAppender());
+    public void resetLogs() {
+        logCaptor.clearLogs();
     }
 
-    @After
-    public void teardownForEachTest() {
-        final org.apache.log4j.Logger strategyLogger = org.apache.log4j.Logger.getLogger(AbstractWarningVerificationStrategy.class);
-        strategyLogger.setLevel(previousLogLevel);
-        Logger.getRootLogger().removeAppender(logAppender);
+    @AfterClass
+    public static void tearDown() {
+        logCaptor.close();
     }
 
     @Parameterized.Parameters(name = "{0}")
@@ -103,7 +99,7 @@ public class EdgeLabelVerificationStrategyTest {
         final Traversal traversal = this.traversal.asAdmin().clone();
         traversal.asAdmin().setStrategies(strategies);
         traversal.asAdmin().applyStrategies();
-        assertThat(repr, logAppender.isEmpty());
+        assertEquals(0, logCaptor.getLogs().size());
     }
 
     @Test
@@ -123,7 +119,7 @@ public class EdgeLabelVerificationStrategyTest {
                 assertThat(repr, MSG_PREDICATE.test(ise.getMessage()));
             }
         }
-        assertThat(repr, logAppender.isEmpty());
+        assertEquals(0, logCaptor.getLogs().size());
     }
 
     @Test
@@ -135,8 +131,8 @@ public class EdgeLabelVerificationStrategyTest {
         traversal.asAdmin().setStrategies(strategies);
         traversal.asAdmin().applyStrategies();
         if (!allow) {
-            assertThat(String.format("Expected log entry not found in %s for %s", logAppender.messages, repr),
-                    logAppender.messages().anyMatch(MSG_PREDICATE));
+            assertThat(String.format("Expected log entry not found in %s for %s", logCaptor.getLogs(), repr),
+                    logCaptor.getLogs().stream().anyMatch(MSG_PREDICATE));
         }
     }
 
@@ -149,7 +145,7 @@ public class EdgeLabelVerificationStrategyTest {
         traversal.asAdmin().setStrategies(strategies);
         if (allow) {
             traversal.asAdmin().applyStrategies();
-            assertThat(repr, logAppender.isEmpty());
+            assertEquals(0, logCaptor.getLogs().size());
         } else {
             try {
                 traversal.asAdmin().applyStrategies();
@@ -157,36 +153,8 @@ public class EdgeLabelVerificationStrategyTest {
             } catch (VerificationException ise) {
                 assertThat(repr, MSG_PREDICATE.test(ise.getMessage()));
             }
-            assertThat(String.format("Expected log entry not found in %s for %s", logAppender.messages, repr),
-                    logAppender.messages().anyMatch(MSG_PREDICATE));
-        }
-    }
-
-    class TestLogAppender extends AppenderSkeleton {
-
-        private List<String> messages = new ArrayList<>();
-
-        boolean isEmpty() {
-            return messages.isEmpty();
-        }
-
-        Stream<String> messages() {
-            return messages.stream();
-        }
-
-        @Override
-        protected void append(org.apache.log4j.spi.LoggingEvent loggingEvent) {
-            messages.add(loggingEvent.getMessage().toString());
-        }
-
-        @Override
-        public void close() {
-
-        }
-
-        @Override
-        public boolean requiresLayout() {
-            return false;
+            assertThat(String.format("Expected log entry not found in %s for %s", logCaptor.getLogs(), repr),
+                    logCaptor.getLogs().stream().anyMatch(MSG_PREDICATE));
         }
     }
 }
\ No newline at end of file
diff --git a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/verification/ReservedKeysVerificationStrategyTest.java b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/verification/ReservedKeysVerificationStrategyTest.java
index f037e39..fa08502 100644
--- a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/verification/ReservedKeysVerificationStrategyTest.java
+++ b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/verification/ReservedKeysVerificationStrategyTest.java
@@ -18,9 +18,7 @@
  */
 package org.apache.tinkerpop.gremlin.process.traversal.strategy.verification;
 
-import org.apache.log4j.AppenderSkeleton;
-import org.apache.log4j.Level;
-import org.apache.log4j.Logger;
+import nl.altindag.log.LogCaptor;
 import org.apache.tinkerpop.gremlin.process.traversal.Translator;
 import org.apache.tinkerpop.gremlin.process.traversal.Traversal;
 import org.apache.tinkerpop.gremlin.process.traversal.TraversalStrategies;
@@ -28,23 +26,20 @@ import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__;
 import org.apache.tinkerpop.gremlin.process.traversal.translator.GroovyTranslator;
 import org.apache.tinkerpop.gremlin.process.traversal.util.DefaultTraversalStrategies;
 import org.apache.tinkerpop.gremlin.structure.T;
-import org.junit.After;
+import org.junit.AfterClass;
 import org.junit.Before;
+import org.junit.BeforeClass;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
 
-import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.HashSet;
-import java.util.List;
 import java.util.function.Predicate;
 import java.util.regex.Pattern;
-import java.util.stream.Stream;
 
 import static org.hamcrest.MatcherAssert.assertThat;
-import static org.hamcrest.core.Is.is;
-import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.fail;
 
 /**
@@ -58,22 +53,21 @@ public class ReservedKeysVerificationStrategyTest {
             ".*that is setting a property key to a reserved word.*")
             .asPredicate();
 
-    private TestLogAppender logAppender;
-    private Level previousLogLevel;
+    private static LogCaptor logCaptor;
+
+    @BeforeClass
+    public static void setupLogCaptor() {
+        logCaptor = LogCaptor.forClass(AbstractWarningVerificationStrategy.class);
+    }
 
     @Before
-    public void setupForEachTest() {
-        final Logger strategyLogger = Logger.getLogger(AbstractWarningVerificationStrategy.class);
-        previousLogLevel = strategyLogger.getLevel();
-        strategyLogger.setLevel(Level.WARN);
-        Logger.getRootLogger().addAppender(logAppender = new TestLogAppender());
+    public void resetLogs() {
+        logCaptor.clearLogs();
     }
 
-    @After
-    public void teardownForEachTest() {
-        final Logger strategyLogger = Logger.getLogger(AbstractWarningVerificationStrategy.class);
-        strategyLogger.setLevel(previousLogLevel);
-        Logger.getRootLogger().removeAppender(logAppender);
+    @AfterClass
+    public static void tearDown() {
+        logCaptor.close();
     }
 
     @Parameterized.Parameters(name = "{0}")
@@ -105,7 +99,7 @@ public class ReservedKeysVerificationStrategyTest {
         final Traversal traversal = this.traversal.asAdmin().clone();
         traversal.asAdmin().setStrategies(strategies);
         traversal.asAdmin().applyStrategies();
-        assertThat(repr, logAppender.isEmpty(), is(true));
+        assertEquals(0, logCaptor.getLogs().size());
     }
 
     @Test
@@ -128,7 +122,7 @@ public class ReservedKeysVerificationStrategyTest {
                 assertThat(repr, MSG_PREDICATE.test(ise.getMessage()));
             }
         }
-        assertThat(repr, logAppender.isEmpty());
+        assertEquals(0, logCaptor.getLogs().size());
     }
 
     @Test
@@ -143,8 +137,8 @@ public class ReservedKeysVerificationStrategyTest {
         traversal.asAdmin().setStrategies(strategies);
         traversal.asAdmin().applyStrategies();
         if (!allow) {
-            assertThat(String.format("Expected log entry not found in %s for %s", logAppender.messages, repr),
-                    logAppender.messages().anyMatch(MSG_PREDICATE));
+            assertThat(String.format("Expected log entry not found in %s for %s", logCaptor.getLogs(), repr),
+                    logCaptor.getLogs().stream().anyMatch(MSG_PREDICATE));
         }
     }
 
@@ -161,7 +155,7 @@ public class ReservedKeysVerificationStrategyTest {
         traversal.asAdmin().setStrategies(strategies);
         if (allow) {
             traversal.asAdmin().applyStrategies();
-            assertThat(repr, logAppender.isEmpty());
+            assertEquals(0, logCaptor.getLogs().size());
         } else {
             try {
                 traversal.asAdmin().applyStrategies();
@@ -169,36 +163,8 @@ public class ReservedKeysVerificationStrategyTest {
             } catch (VerificationException ise) {
                 assertThat(repr, MSG_PREDICATE.test(ise.getMessage()));
             }
-            assertTrue(String.format("Expected log entry not found in %s for %s", logAppender.messages, repr),
-                    logAppender.messages().anyMatch(MSG_PREDICATE));
-        }
-    }
-
-    class TestLogAppender extends AppenderSkeleton {
-
-        private List<String> messages = new ArrayList<>();
-
-        boolean isEmpty() {
-            return messages.isEmpty();
-        }
-
-        Stream<String> messages() {
-            return messages.stream();
-        }
-
-        @Override
-        protected void append(org.apache.log4j.spi.LoggingEvent loggingEvent) {
-            messages.add(loggingEvent.getMessage().toString());
-        }
-
-        @Override
-        public void close() {
-
-        }
-
-        @Override
-        public boolean requiresLayout() {
-            return false;
+            assertThat(String.format("Expected log entry not found in %s for %s", logCaptor.getLogs(), repr),
+                    logCaptor.getLogs().stream().anyMatch(MSG_PREDICATE));
         }
     }
 }
\ No newline at end of file
diff --git a/gremlin-core/src/test/resources/log4j-silent.properties b/gremlin-core/src/test/resources/log4j-silent.properties
deleted file mode 100644
index d639ca7..0000000
--- a/gremlin-core/src/test/resources/log4j-silent.properties
+++ /dev/null
@@ -1,27 +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.
-
-# this file should always have logging set to OFF.  it seems, however, that an appender of some sort is
-# required or else some logs throw error and use other log4j.properties files on the path.
-log4j.rootLogger=OFF, stdout
-log4j.appender.stdout=org.apache.log4j.ConsoleAppender
-log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
-log4j.appender.stdout.layout.ConversionPattern=[%p] %C - %m%n
-
-# need to turn this on so that we know the test seed
-log4j.logger.org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalTest=INFO
-log4j.logger.org.apache.tinkerpop.gremlin.TestHelper=INFO
\ No newline at end of file
diff --git a/gremlin-core/src/test/resources/log4j-test.properties b/gremlin-core/src/test/resources/log4j-test.properties
deleted file mode 100644
index b46385a..0000000
--- a/gremlin-core/src/test/resources/log4j-test.properties
+++ /dev/null
@@ -1,25 +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.
-
-log4j.rootLogger=WARN, stdout
-log4j.appender.stdout=org.apache.log4j.ConsoleAppender
-log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
-log4j.appender.stdout.layout.ConversionPattern=[%p] %C - %m%n
-
-# need to turn this on so that we know the test seed
-log4j.logger.org.apache.tinkerpop.gremlin.TestHelper=INFO
-log4j.logger.org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalTest=INFO
\ No newline at end of file
diff --git a/gremlin-core/src/test/resources/logback-silent.xml b/gremlin-core/src/test/resources/logback-silent.xml
new file mode 100644
index 0000000..59ab036
--- /dev/null
+++ b/gremlin-core/src/test/resources/logback-silent.xml
@@ -0,0 +1,29 @@
+<!--
+Licensed to the Apache Software Foundation (ASF) under one or more
+contributor license agreements.  See the NOTICE file distributed with
+this work for additional information regarding copyright ownership.
+The ASF licenses this file to You under the Apache License, Version 2.0
+(the "License"); you may not use this file except in compliance with
+the License.  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+-->
+<configuration>
+    <appender name="stdout" class="ch.qos.logback.core.ConsoleAppender">
+        <encoder>
+            <pattern>[%p] %C - %m%n</pattern>
+        </encoder>
+    </appender>
+    <logger name="org.apache.tinkerpop.gremlin.TestHelper" level="INFO"/>
+    <logger name="org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalTest" level="INFO"/>
+    <logger name="org.apache.tinkerpop.gremlin.process.traversal.strategy.verification.AbstractWarningVerificationStrategy" level="WARN"/>
+    <root level="OFF">
+        <appender-ref ref="stdout"/>
+    </root>
+</configuration>
\ No newline at end of file
diff --git a/gremlin-core/src/test/resources/logback-test.xml b/gremlin-core/src/test/resources/logback-test.xml
new file mode 100644
index 0000000..5215f9e
--- /dev/null
+++ b/gremlin-core/src/test/resources/logback-test.xml
@@ -0,0 +1,28 @@
+<!--
+Licensed to the Apache Software Foundation (ASF) under one or more
+contributor license agreements.  See the NOTICE file distributed with
+this work for additional information regarding copyright ownership.
+The ASF licenses this file to You under the Apache License, Version 2.0
+(the "License"); you may not use this file except in compliance with
+the License.  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+-->
+<configuration>
+    <appender name="stdout" class="ch.qos.logback.core.ConsoleAppender">
+        <encoder>
+            <pattern>[%p] %C - %m%n</pattern>
+        </encoder>
+    </appender>
+    <logger name="org.apache.tinkerpop.gremlin.TestHelper" level="INFO"/>
+    <logger name="org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalTest" level="INFO"/>
+    <root level="WARN">
+        <appender-ref ref="stdout"/>
+    </root>
+</configuration>
\ No newline at end of file
diff --git a/gremlin-dotnet/src/pom.xml b/gremlin-dotnet/src/pom.xml
index b13306c..22a6e7c 100644
--- a/gremlin-dotnet/src/pom.xml
+++ b/gremlin-dotnet/src/pom.xml
@@ -311,9 +311,9 @@ file.write(file.getText("UTF-8").replaceFirst(/&lt;version&gt;(.*)&lt;\/version&
                                 <scope>runtime</scope>
                             </dependency>
                             <dependency>
-                                <groupId>log4j</groupId>
-                                <artifactId>log4j</artifactId>
-                                <version>1.2.17</version>
+                                <groupId>ch.qos.logback</groupId>
+                                <artifactId>logback-classic</artifactId>
+                                <version>${logback.version}</version>
                                 <scope>runtime</scope>
                             </dependency>
                         </dependencies>
diff --git a/gremlin-dotnet/test/pom.xml b/gremlin-dotnet/test/pom.xml
index 18165fd..1716b5c 100644
--- a/gremlin-dotnet/test/pom.xml
+++ b/gremlin-dotnet/test/pom.xml
@@ -113,9 +113,9 @@ limitations under the License.
                                 <version>${project.version}</version>
                             </dependency>
                             <dependency>
-                                <groupId>log4j</groupId>
-                                <artifactId>log4j</artifactId>
-                                <version>${log4j.version}</version>
+                                <groupId>ch.qos.logback</groupId>
+                                <artifactId>logback-classic</artifactId>
+                                <version>${logback.version}</version>
                                 <scope>runtime</scope>
                             </dependency>
                             <dependency>
diff --git a/gremlin-driver/pom.xml b/gremlin-driver/pom.xml
index c4763f3..17c4243 100644
--- a/gremlin-driver/pom.xml
+++ b/gremlin-driver/pom.xml
@@ -62,13 +62,8 @@ limitations under the License.
             <artifactId>commons-lang3</artifactId>
         </dependency>
         <dependency>
-            <groupId>org.slf4j</groupId>
-            <artifactId>slf4j-log4j12</artifactId>
-            <optional>true</optional>
-        </dependency>
-        <dependency>
-            <groupId>log4j</groupId>
-            <artifactId>log4j</artifactId>
+            <groupId>ch.qos.logback</groupId>
+            <artifactId>logback-classic</artifactId>
             <optional>true</optional>
         </dependency>
         <!-- TinkerGraph is an optional dependency that is only required if doing deserialization of Graph instances -->
@@ -96,6 +91,11 @@ limitations under the License.
             <scope>test</scope>
         </dependency>
         <dependency>
+            <groupId>io.github.hakky54</groupId>
+            <artifactId>logcaptor</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
             <groupId>org.powermock</groupId>
             <artifactId>powermock-module-junit4</artifactId>
             <scope>test</scope>
@@ -169,8 +169,7 @@ limitations under the License.
                                 <!-- exclude logging stuff from uberjar - shading prevents proper logger initialization -->
                                 <!-- exclude groovy as it's only needed for json serialization and is an optional dependency -->
                                 <excludes>
-                                    <exclude>log4j:log4j</exclude>
-                                    <exclude>org.slf4j:slf4j-log4j12</exclude>
+                                    <exclude>ch.qos.logback:logback-classic</exclude>
                                     <exclude>org.slf4j:slf4j-api</exclude>
                                     <exclude>org.slf4j:jcl-over-slf4j</exclude>
                                     <exclude>org.codehaus.groovy:groovy</exclude>
diff --git a/gremlin-driver/src/main/bin/config-eval.sh b/gremlin-driver/src/main/bin/config-eval.sh
index 764d732..c247d8c 100644
--- a/gremlin-driver/src/main/bin/config-eval.sh
+++ b/gremlin-driver/src/main/bin/config-eval.sh
@@ -42,4 +42,4 @@ if [ "$JAVA_OPTIONS" = "" ] ; then
 fi
 
 # Execute the application and return its exit code
-exec $JAVA -Dlog4j.configuration=conf/log4j-driver.properties $JAVA_OPTIONS -cp $CP org.apache.tinkerpop.gremlin.driver.util.ConfigurationEvaluator "$@"
\ No newline at end of file
+exec $JAVA -Dlogback.configurationFile=conf/logback.xml $JAVA_OPTIONS -cp $CP org.apache.tinkerpop.gremlin.driver.util.ConfigurationEvaluator "$@"
\ No newline at end of file
diff --git a/gremlin-driver/src/main/bin/profile-driver.sh b/gremlin-driver/src/main/bin/profile-driver.sh
index 7b4ac1b..60e32e5 100644
--- a/gremlin-driver/src/main/bin/profile-driver.sh
+++ b/gremlin-driver/src/main/bin/profile-driver.sh
@@ -42,4 +42,4 @@ if [ "$JAVA_OPTIONS" = "" ] ; then
 fi
 
 # Execute the application and return its exit code
-exec $JAVA -Dlog4j.configuration=conf/log4j-driver.properties $JAVA_OPTIONS -cp $CP org.apache.tinkerpop.gremlin.driver.util.ProfilingApplication "$@"
\ No newline at end of file
+exec $JAVA -Dlogback.configurationFile=conf/logback.xml $JAVA_OPTIONS -cp $CP org.apache.tinkerpop.gremlin.driver.util.ProfilingApplication "$@"
\ No newline at end of file
diff --git a/gremlin-driver/src/main/conf/log4j-driver.properties b/gremlin-driver/src/main/conf/log4j-driver.properties
deleted file mode 100644
index 129bf4b..0000000
--- a/gremlin-driver/src/main/conf/log4j-driver.properties
+++ /dev/null
@@ -1,25 +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.
-log4j.rootLogger=OFF, stdout
-log4j.logger.org.apache.tinkerpop.gremlin.driver.Connection=OFF
-log4j.logger.org.apache.tinkerpop.gremlin.driver.ConnectionPool=OFF
-log4j.appender.stdout=org.apache.log4j.ConsoleAppender
-#log4j.appender.stdout=org.apache.log4j.FileAppender
-#log4j.appender.stdout.file=recless.log
-#log4j.appender.stdout.append=true
-log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
-log4j.appender.stdout.layout.ConversionPattern=[%p] %C{1} - %m%n
diff --git a/gremlin-driver/src/main/conf/logback.xml b/gremlin-driver/src/main/conf/logback.xml
new file mode 100644
index 0000000..1813c89
--- /dev/null
+++ b/gremlin-driver/src/main/conf/logback.xml
@@ -0,0 +1,28 @@
+<!--
+Licensed to the Apache Software Foundation (ASF) under one or more
+contributor license agreements.  See the NOTICE file distributed with
+this work for additional information regarding copyright ownership.
+The ASF licenses this file to You under the Apache License, Version 2.0
+(the "License"); you may not use this file except in compliance with
+the License.  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+-->
+<configuration>
+    <appender name="stdout" class="ch.qos.logback.core.ConsoleAppender">
+        <encoder>
+            <pattern>[%p] %C{1} - %m%n</pattern>
+        </encoder>
+    </appender>
+    <logger name="org.apache.tinkerpop.gremlin.driver.Connection" level="OFF"/>
+    <logger name="org.apache.tinkerpop.gremlin.driver.ConnectionPool" level="OFF"/>
+    <root level="OFF">
+        <appender-ref ref="stdout"/>
+    </root>
+</configuration>
\ No newline at end of file
diff --git a/gremlin-driver/src/main/static/LICENSE b/gremlin-driver/src/main/static/LICENSE
index c7f7809..7b2bc04 100644
--- a/gremlin-driver/src/main/static/LICENSE
+++ b/gremlin-driver/src/main/static/LICENSE
@@ -229,6 +229,12 @@ The Apache TinkerPop project bundles the following components under the MIT Lice
      SLF4J API Module (org.slf4j:slf4j-api:1.7.25 - http://www.slf4j.org)
        - shaded to org.shaded.slf4j
        - for details, see licenses/slf4j
-     SLF4J LOG4J-12 Binding (org.slf4j:slf4j-log4j12:1.7.25 - http://www.slf4j.org)
-       - shaded to org.shaded.slf4j
-       - for details, see licenses/slf4j
+
+========================================================================
+Other Licenses
+========================================================================
+
+The Apache TinkerPop project bundles the following components under the Eclipse Public License 1.0:
+
+     logback-core (ch.qos.logback:logback-core:1.2.3 - https://logback.qos.ch) - for details, see licenses/logback
+     logback-classic (ch.qos.logback:logback-classic:1.2.3 - https://logback.qos.ch) - for details, see licenses/logback
\ No newline at end of file
diff --git a/gremlin-driver/src/main/static/licenses/logback b/gremlin-driver/src/main/static/licenses/logback
new file mode 100644
index 0000000..8953762
--- /dev/null
+++ b/gremlin-driver/src/main/static/licenses/logback
@@ -0,0 +1,14 @@
+Logback LICENSE
+---------------
+
+Logback: the reliable, generic, fast and flexible logging framework.
+Copyright (C) 1999-2015, QOS.ch. All rights reserved.
+
+This program and the accompanying materials are dual-licensed under
+either the terms of the Eclipse Public License v1.0 as published by
+the Eclipse Foundation
+
+  or (per the licensee's choosing)
+
+under the terms of the GNU Lesser General Public License version 2.1
+as published by the Free Software Foundation.
\ No newline at end of file
diff --git a/gremlin-driver/src/main/static/licenses/slf4j b/gremlin-driver/src/main/static/licenses/slf4j
new file mode 100644
index 0000000..e106b98
--- /dev/null
+++ b/gremlin-driver/src/main/static/licenses/slf4j
@@ -0,0 +1,21 @@
+ Copyright (c) 2004-2017 QOS.ch
+ All rights reserved.
+
+ Permission is hereby granted, free  of charge, to any person obtaining
+ a  copy  of this  software  and  associated  documentation files  (the
+ "Software"), to  deal in  the Software without  restriction, including
+ without limitation  the rights to  use, copy, modify,  merge, publish,
+ distribute,  sublicense, and/or sell  copies of  the Software,  and to
+ permit persons to whom the Software  is furnished to do so, subject to
+ the following conditions:
+
+ The  above  copyright  notice  and  this permission  notice  shall  be
+ included in all copies or substantial portions of the Software.
+
+ THE  SOFTWARE IS  PROVIDED  "AS  IS", WITHOUT  WARRANTY  OF ANY  KIND,
+ EXPRESS OR  IMPLIED, INCLUDING  BUT NOT LIMITED  TO THE  WARRANTIES OF
+ MERCHANTABILITY,    FITNESS    FOR    A   PARTICULAR    PURPOSE    AND
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ OF CONTRACT, TORT OR OTHERWISE,  ARISING FROM, OUT OF OR IN CONNECTION
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
\ No newline at end of file
diff --git a/gremlin-driver/src/test/java/org/apache/tinkerpop/gremlin/driver/ClientTest.java b/gremlin-driver/src/test/java/org/apache/tinkerpop/gremlin/driver/ClientTest.java
index 1ca2aeb..d7a693f 100644
--- a/gremlin-driver/src/test/java/org/apache/tinkerpop/gremlin/driver/ClientTest.java
+++ b/gremlin-driver/src/test/java/org/apache/tinkerpop/gremlin/driver/ClientTest.java
@@ -23,6 +23,7 @@ import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.Mock;
+import org.powermock.core.classloader.annotations.PowerMockIgnore;
 import org.powermock.core.classloader.annotations.PrepareForTest;
 import org.powermock.modules.junit4.PowerMockRunner;
 
@@ -38,6 +39,7 @@ import static org.powermock.api.mockito.PowerMockito.whenNew;
 
 @RunWith(PowerMockRunner.class)
 @PrepareForTest({Client.ClusteredClient.class, Client.SessionedClient.class, Host.class, Cluster.class})
+@PowerMockIgnore({"com.sun.org.apache.xerces.*", "javax.xml.*", "org.xml.*", "javax.management.*"})
 public class ClientTest {
     @Mock
     private Cluster cluster;
diff --git a/gremlin-driver/src/test/java/org/apache/tinkerpop/gremlin/driver/WebSocketClientBehaviorIntegrateTest.java b/gremlin-driver/src/test/java/org/apache/tinkerpop/gremlin/driver/WebSocketClientBehaviorIntegrateTest.java
index 0eb34f6..d6560ea 100644
--- a/gremlin-driver/src/test/java/org/apache/tinkerpop/gremlin/driver/WebSocketClientBehaviorIntegrateTest.java
+++ b/gremlin-driver/src/test/java/org/apache/tinkerpop/gremlin/driver/WebSocketClientBehaviorIntegrateTest.java
@@ -18,17 +18,19 @@
  */
 package org.apache.tinkerpop.gremlin.driver;
 
+import nl.altindag.log.LogCaptor;
+import org.apache.tinkerpop.gremlin.process.traversal.strategy.verification.AbstractWarningVerificationStrategy;
 import org.junit.After;
+import org.junit.AfterClass;
 import org.junit.Before;
+import org.junit.BeforeClass;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.rules.TestName;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
-import org.apache.log4j.Level;
 import org.apache.tinkerpop.gremlin.driver.ser.Serializers;
 import org.apache.tinkerpop.gremlin.structure.Vertex;
-import org.apache.tinkerpop.gremlin.util.Log4jRecordingAppender;
 
 import java.util.concurrent.CompletableFuture;
 import java.util.concurrent.ExecutionException;
@@ -43,28 +45,28 @@ import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
 
 public class WebSocketClientBehaviorIntegrateTest {
+    private static final Logger logger = LoggerFactory.getLogger(WebSocketClientBehaviorIntegrateTest.class);
+
     @Rule
     public TestName name = new TestName();
 
-    private static final Logger logger = LoggerFactory.getLogger(WebSocketClientBehaviorIntegrateTest.class);
-    private Log4jRecordingAppender recordingAppender = null;
-    private Level previousLogLevel;
+    private static LogCaptor logCaptor;
+
     private SimpleSocketServer server;
 
+    @BeforeClass
+    public static void setupLogCaptor() {
+        logCaptor = LogCaptor.forClass(AbstractWarningVerificationStrategy.class);
+    }
+
+    @AfterClass
+    public static void tearDown() {
+        logCaptor.close();
+    }
+
     @Before
     public void setUp() throws InterruptedException {
-        recordingAppender = new Log4jRecordingAppender();
-        final org.apache.log4j.Logger rootLogger = org.apache.log4j.Logger.getRootLogger();
-        if (name.getMethodName().equals("shouldRemoveConnectionFromPoolWhenServerClose_WithPendingRequests") ||
-                name.getMethodName().equals("shouldNotCreateReplacementConnectionWhenClientClosesConnection")) {
-            final org.apache.log4j.Logger connectionPoolLogger = org.apache.log4j.Logger.getLogger(ConnectionPool.class);
-            final org.apache.log4j.Logger connectionLogger = org.apache.log4j.Logger.getLogger(Connection.class);
-            previousLogLevel = connectionPoolLogger.getLevel();
-            connectionPoolLogger.setLevel(Level.DEBUG);
-            connectionLogger.setLevel(Level.DEBUG);
-        }
-
-        rootLogger.addAppender(recordingAppender);
+        logCaptor.clearLogs();
 
         server = new SimpleSocketServer();
         server.start(new TestWSGremlinInitializer());
@@ -73,19 +75,6 @@ public class WebSocketClientBehaviorIntegrateTest {
     @After
     public void shutdown() {
         server.stop();
-
-        // reset logger
-        final org.apache.log4j.Logger rootLogger = org.apache.log4j.Logger.getRootLogger();
-
-        if (name.getMethodName().equals("shouldRemoveConnectionFromPoolWhenServerClose_WithPendingRequests") ||
-                name.getMethodName().equals("shouldNotCreateReplacementConnectionWhenClientClosesConnection")) {
-            final org.apache.log4j.Logger connectionPoolLogger = org.apache.log4j.Logger.getLogger(ConnectionPool.class);
-            final org.apache.log4j.Logger connectionLogger = org.apache.log4j.Logger.getLogger(Connection.class);
-            connectionPoolLogger.setLevel(previousLogLevel);
-            connectionLogger.setLevel(previousLogLevel);
-        }
-
-        rootLogger.removeAppender(recordingAppender);
     }
 
     /**
@@ -226,7 +215,7 @@ public class WebSocketClientBehaviorIntegrateTest {
         Thread.sleep(2000);
 
         // Assert that we should consider creating a connection only once, since only one connection is being closed.
-        assertEquals(1, recordingAppender.getMessages().stream().filter(str -> str.contains("Considering new connection on")).count());
+        assertEquals(1, logCaptor.getLogs().stream().filter(str -> str.contains("Considering new connection on")).count());
 
         // assert sanity after connection replacement
         final Vertex v = client.submit("1",
@@ -262,13 +251,9 @@ public class WebSocketClientBehaviorIntegrateTest {
         Thread.sleep(2000);
 
         assertEquals("OnClose callback should be called but only once", 1,
-                recordingAppender.getMessages().stream()
-                        .filter(str -> str.contains("OnChannelClose callback called for channel"))
-                        .count());
+                logCaptor.getLogs().stream().filter(str -> str.contains("OnChannelClose callback called for channel")).count());
 
         assertEquals("No new connection creation should be started", 0,
-                recordingAppender.getMessages().stream()
-                        .filter(str -> str.contains("Considering new connection on"))
-                        .count());
+                logCaptor.getLogs().stream().filter(str -> str.contains("Considering new connection on")).count());
     }
 }
\ No newline at end of file
diff --git a/gremlin-driver/src/test/java/org/apache/tinkerpop/gremlin/driver/ser/GraphSONMessageSerializerV2d0Test.java b/gremlin-driver/src/test/java/org/apache/tinkerpop/gremlin/driver/ser/GraphSONMessageSerializerV2d0Test.java
index 897b759..e34309c 100644
--- a/gremlin-driver/src/test/java/org/apache/tinkerpop/gremlin/driver/ser/GraphSONMessageSerializerV2d0Test.java
+++ b/gremlin-driver/src/test/java/org/apache/tinkerpop/gremlin/driver/ser/GraphSONMessageSerializerV2d0Test.java
@@ -21,7 +21,6 @@ package org.apache.tinkerpop.gremlin.driver.ser;
 import io.netty.buffer.ByteBuf;
 import io.netty.buffer.ByteBufAllocator;
 import io.netty.buffer.UnpooledByteBufAllocator;
-import org.apache.log4j.Level;
 import org.apache.tinkerpop.gremlin.driver.MessageSerializer;
 import org.apache.tinkerpop.gremlin.driver.message.RequestMessage;
 import org.apache.tinkerpop.gremlin.driver.message.ResponseMessage;
@@ -566,14 +565,8 @@ public class GraphSONMessageSerializerV2d0Test {
     @Test
     @SuppressWarnings("deprecation")
     public void shouldFailOnMessageSerializerWithMapperIfNoGremlinServerModule() {
-        org.apache.log4j.Logger logger = org.apache.log4j.Logger.getLogger(AbstractGraphSONMessageSerializerV2d0.class);
-        Level previousLevel = logger.getLevel();
-
-        // Disable temporarily logging for this test
-        logger.setLevel(Level.OFF);
-
-        GraphSONMapper.Builder builder = GraphSONMapper.build().addCustomModule(GraphSONXModuleV2d0.build().create(false));
-        GraphSONMessageSerializerV2d0 graphSONMessageSerializerV2d0 = new GraphSONMessageSerializerV2d0(builder.create());
+        final GraphSONMapper.Builder builder = GraphSONMapper.build().addCustomModule(GraphSONXModuleV2d0.build().create(false));
+        final GraphSONMessageSerializerV2d0 graphSONMessageSerializerV2d0 = new GraphSONMessageSerializerV2d0(builder.create());
 
         try {
             convert("hello", graphSONMessageSerializerV2d0);
@@ -583,9 +576,6 @@ public class GraphSONMessageSerializerV2d0Test {
             assertTrue(e.getCause() instanceof JsonMappingException);
             assertTrue(e.getCause().getCause() instanceof IllegalArgumentException);
         }
-
-        // Put logger level back to its original value
-        logger.setLevel(previousLevel);
     }
 
     private ResponseMessage convert(final Object toSerialize, MessageSerializer<?> serializer) throws SerializationException {
diff --git a/gremlin-driver/src/test/java/org/apache/tinkerpop/gremlin/driver/ser/GraphSONMessageSerializerV3d0Test.java b/gremlin-driver/src/test/java/org/apache/tinkerpop/gremlin/driver/ser/GraphSONMessageSerializerV3d0Test.java
index 29de3c3..dce52c7 100644
--- a/gremlin-driver/src/test/java/org/apache/tinkerpop/gremlin/driver/ser/GraphSONMessageSerializerV3d0Test.java
+++ b/gremlin-driver/src/test/java/org/apache/tinkerpop/gremlin/driver/ser/GraphSONMessageSerializerV3d0Test.java
@@ -21,8 +21,6 @@ package org.apache.tinkerpop.gremlin.driver.ser;
 import io.netty.buffer.ByteBuf;
 import io.netty.buffer.ByteBufAllocator;
 import io.netty.buffer.UnpooledByteBufAllocator;
-import org.apache.log4j.Level;
-import org.apache.log4j.Logger;
 import org.apache.tinkerpop.gremlin.driver.MessageSerializer;
 import org.apache.tinkerpop.gremlin.driver.message.RequestMessage;
 import org.apache.tinkerpop.gremlin.driver.message.ResponseMessage;
@@ -360,14 +358,8 @@ public class GraphSONMessageSerializerV3d0Test {
 
     @Test
     public void shouldFailOnMessageSerializerWithMapperIfNoGremlinServerModule() {
-        Logger logger = Logger.getLogger(AbstractGraphSONMessageSerializerV2d0.class);
-        Level previousLevel = logger.getLevel();
-
-        // Disable temporarily logging for this test
-        logger.setLevel(Level.OFF);
-
-        GraphSONMapper.Builder builder = GraphSONMapper.build().addCustomModule(GraphSONXModuleV3d0.build().create(false));
-        GraphSONMessageSerializerV3d0 graphSONMessageSerializerV3d0 = new GraphSONMessageSerializerV3d0(builder.create());
+        final GraphSONMapper.Builder builder = GraphSONMapper.build().addCustomModule(GraphSONXModuleV3d0.build().create(false));
+        final GraphSONMessageSerializerV3d0 graphSONMessageSerializerV3d0 = new GraphSONMessageSerializerV3d0(builder.create());
 
         try {
             convert("hello", graphSONMessageSerializerV3d0);
@@ -377,9 +369,6 @@ public class GraphSONMessageSerializerV3d0Test {
             assertTrue(e.getCause() instanceof JsonMappingException);
             assertTrue(e.getCause().getCause() instanceof IllegalArgumentException);
         }
-
-        // Put logger level back to its original value
-        logger.setLevel(previousLevel);
     }
 
     private void assertCommon(final ResponseMessage response) {
diff --git a/gremlin-driver/src/test/java/org/apache/tinkerpop/gremlin/util/Log4jRecordingAppender.java b/gremlin-driver/src/test/java/org/apache/tinkerpop/gremlin/util/Log4jRecordingAppender.java
deleted file mode 100644
index 89321ed..0000000
--- a/gremlin-driver/src/test/java/org/apache/tinkerpop/gremlin/util/Log4jRecordingAppender.java
+++ /dev/null
@@ -1,86 +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.tinkerpop.gremlin.util;
-
-import org.apache.log4j.AppenderSkeleton;
-import org.apache.log4j.Level;
-import org.apache.log4j.PatternLayout;
-import org.apache.log4j.spi.LoggingEvent;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.regex.Pattern;
-
-/**
- * Provides a way to gather logging events for purpose of testing log output.
- *
- * @author Stephen Mallette (http://stephen.genoprime.com)
- */
-public class Log4jRecordingAppender extends AppenderSkeleton {
-    private final List<String> messages = new ArrayList<>();
-    private final List<LoggingEvent> events = new ArrayList<>();
-
-    public Log4jRecordingAppender() {
-        super();
-        setLayout(new PatternLayout("%p - %m%n")); // note the EOLN char(s) appended
-    }
-
-    @Override
-    protected void append(final LoggingEvent event) {
-        messages.add(layout.format(event));
-        events.add(event);
-    }
-
-    @Override
-    public void close() {
-    }
-
-    @Override
-    public boolean requiresLayout() {
-        return true;
-    }
-
-    public List<String> getMessages() { return messages; }
-
-    public List<LoggingEvent> getEvents() { return events; }
-
-    public void clear() {
-        messages.clear();
-    }
-
-    /**
-     * @param regex not null
-     * @return true if there is a substring of a message matching the regular expression, where:
-     *         . matches also the EOLN char(s) defined in the layout.
-     *         $ matches the end of the string
-     */
-    public boolean logContainsAny(final String regex) {
-        Pattern pattern = Pattern.compile(regex, Pattern.DOTALL);
-        return messages.stream().anyMatch(m -> pattern.matcher( m ).find());
-    }
-
-    public boolean logContainsAny(final String loggerName, final Level level, final String fragment) {
-        return events.stream().anyMatch(m -> m.getLoggerName().equals(loggerName) &&
-                m.getLevel().equals(level) && m.getMessage().toString().contains(fragment));
-    }
-    public boolean logMatchesAny(final String loggerName, final Level level, final String regex) {
-        return events.stream().anyMatch(m -> m.getLoggerName().equals(loggerName) &&
-                m.getLevel().equals(level) && m.getMessage().toString().matches(regex));
-    }
-}
diff --git a/gremlin-driver/src/test/java/org/apache/tinkerpop/gremlin/util/Log4jRecordingAppenderTest.java b/gremlin-driver/src/test/java/org/apache/tinkerpop/gremlin/util/Log4jRecordingAppenderTest.java
deleted file mode 100644
index 05cb437..0000000
--- a/gremlin-driver/src/test/java/org/apache/tinkerpop/gremlin/util/Log4jRecordingAppenderTest.java
+++ /dev/null
@@ -1,86 +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.tinkerpop.gremlin.util;
-
-import org.apache.log4j.Level;
-import org.apache.log4j.Logger;
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.slf4j.LoggerFactory;
-
-import static org.hamcrest.CoreMatchers.is;
-import static org.junit.Assert.assertEquals;
-import static org.hamcrest.MatcherAssert.assertThat;
-
-/**
- * @author Stephen Mallette (http://stephen.genoprime.com)
- */
-public class Log4jRecordingAppenderTest {
-    private static final org.slf4j.Logger logger = LoggerFactory.getLogger(Log4jRecordingAppenderTest.class);
-    private Log4jRecordingAppender recordingAppender = null;
-    private static final String lineSeparator = System.getProperty("line.separator");
-
-    private Level originalConfiguredLevel = null;
-
-    @Before
-    public void setupForEachTest() {
-        recordingAppender = new Log4jRecordingAppender();
-        final Logger rootLogger = Logger.getRootLogger();
-        if (null == originalConfiguredLevel) originalConfiguredLevel = rootLogger.getLevel();
-        rootLogger.addAppender(recordingAppender);
-        rootLogger.setLevel(Level.ALL);
-
-        logger.error("ERROR");
-        logger.warn("WARN");
-        logger.info("INFO");
-    }
-
-    @After
-    public void teardownForEachTest() {
-        final Logger rootLogger = Logger.getRootLogger();
-        rootLogger.removeAppender(recordingAppender);
-        rootLogger.setLevel(originalConfiguredLevel);
-    }
-
-    @Test
-    public void shouldRecordMessages() {
-        assertEquals(3, recordingAppender.getMessages().size());
-        assertEquals("ERROR - ERROR" + lineSeparator, recordingAppender.getMessages().get(0));
-        assertEquals("WARN - WARN"  + lineSeparator, recordingAppender.getMessages().get(1));
-        assertEquals("INFO - INFO" + lineSeparator, recordingAppender.getMessages().get(2));
-    }
-
-    @Test
-    public void shouldMatchAnyMessages() {
-        assertThat(recordingAppender.logContainsAny("ERROR.*"), is(true));
-    }
-
-    @Test
-    public void shouldMatchNoMessages() {
-        assertThat(recordingAppender.logContainsAny("this is not here"), is(false));
-    }
-
-    @Test
-    public void shouldClearMessages() {
-        assertEquals(3, recordingAppender.getMessages().size());
-        recordingAppender.clear();
-        assertEquals(0, recordingAppender.getMessages().size());
-    }
-}
diff --git a/gremlin-driver/src/test/resources/log4j-silent.properties b/gremlin-driver/src/test/resources/log4j-silent.properties
deleted file mode 100644
index 1825bb0..0000000
--- a/gremlin-driver/src/test/resources/log4j-silent.properties
+++ /dev/null
@@ -1,23 +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.
-
-# this file should always have logging set to OFF.  it seems, however, that an appender of some sort is
-# required or else some logs throw error and use other log4j.properties files on the path.
-log4j.rootLogger=OFF, stdout
-log4j.appender.stdout=org.apache.log4j.ConsoleAppender
-log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
-log4j.appender.stdout.layout.ConversionPattern=[%p] %C - %m%n
\ No newline at end of file
diff --git a/gremlin-driver/src/test/resources/log4j-test.properties b/gremlin-driver/src/test/resources/log4j-test.properties
deleted file mode 100644
index ef436fe..0000000
--- a/gremlin-driver/src/test/resources/log4j-test.properties
+++ /dev/null
@@ -1,21 +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.
-
-log4j.rootLogger=WARN, stdout
-log4j.appender.stdout=org.apache.log4j.ConsoleAppender
-log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
-log4j.appender.stdout.layout.ConversionPattern=[%p] %C - %m%n
\ No newline at end of file
diff --git a/gremlin-driver/src/test/resources/logback-silent.xml b/gremlin-driver/src/test/resources/logback-silent.xml
new file mode 100644
index 0000000..4c5947d
--- /dev/null
+++ b/gremlin-driver/src/test/resources/logback-silent.xml
@@ -0,0 +1,26 @@
+<!--
+Licensed to the Apache Software Foundation (ASF) under one or more
+contributor license agreements.  See the NOTICE file distributed with
+this work for additional information regarding copyright ownership.
+The ASF licenses this file to You under the Apache License, Version 2.0
+(the "License"); you may not use this file except in compliance with
+the License.  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+-->
+<configuration>
+    <appender name="stdout" class="ch.qos.logback.core.ConsoleAppender">
+        <encoder>
+            <pattern>[%p] %C - %m%n</pattern>
+        </encoder>
+    </appender>
+    <root level="OFF">
+        <appender-ref ref="stdout"/>
+    </root>
+</configuration>
\ No newline at end of file
diff --git a/gremlin-driver/src/test/resources/logback-test.xml b/gremlin-driver/src/test/resources/logback-test.xml
new file mode 100644
index 0000000..5d94c3b
--- /dev/null
+++ b/gremlin-driver/src/test/resources/logback-test.xml
@@ -0,0 +1,26 @@
+<!--
+Licensed to the Apache Software Foundation (ASF) under one or more
+contributor license agreements.  See the NOTICE file distributed with
+this work for additional information regarding copyright ownership.
+The ASF licenses this file to You under the Apache License, Version 2.0
+(the "License"); you may not use this file except in compliance with
+the License.  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+-->
+<configuration>
+    <appender name="stdout" class="ch.qos.logback.core.ConsoleAppender">
+        <encoder>
+            <pattern>[%p] %C - %m%n</pattern>
+        </encoder>
+    </appender>
+    <root level="WARN">
+        <appender-ref ref="stdout"/>
+    </root>
+</configuration>
\ No newline at end of file
diff --git a/gremlin-groovy/pom.xml b/gremlin-groovy/pom.xml
index 033f2f1..ded8358 100644
--- a/gremlin-groovy/pom.xml
+++ b/gremlin-groovy/pom.xml
@@ -104,8 +104,8 @@ limitations under the License.
             <scope>test</scope>
         </dependency>
         <dependency>
-            <groupId>org.slf4j</groupId>
-            <artifactId>slf4j-log4j12</artifactId>
+            <groupId>ch.qos.logback</groupId>
+            <artifactId>logback-classic</artifactId>
             <scope>test</scope>
         </dependency>
         <dependency>
diff --git a/gremlin-groovy/src/test/resources/log4j-silent.properties b/gremlin-groovy/src/test/resources/log4j-silent.properties
deleted file mode 100644
index 1825bb0..0000000
--- a/gremlin-groovy/src/test/resources/log4j-silent.properties
+++ /dev/null
@@ -1,23 +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.
-
-# this file should always have logging set to OFF.  it seems, however, that an appender of some sort is
-# required or else some logs throw error and use other log4j.properties files on the path.
-log4j.rootLogger=OFF, stdout
-log4j.appender.stdout=org.apache.log4j.ConsoleAppender
-log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
-log4j.appender.stdout.layout.ConversionPattern=[%p] %C - %m%n
\ No newline at end of file
diff --git a/gremlin-groovy/src/test/resources/log4j-test.properties b/gremlin-groovy/src/test/resources/log4j-test.properties
deleted file mode 100644
index ef436fe..0000000
--- a/gremlin-groovy/src/test/resources/log4j-test.properties
+++ /dev/null
@@ -1,21 +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.
-
-log4j.rootLogger=WARN, stdout
-log4j.appender.stdout=org.apache.log4j.ConsoleAppender
-log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
-log4j.appender.stdout.layout.ConversionPattern=[%p] %C - %m%n
\ No newline at end of file
diff --git a/gremlin-groovy/src/test/resources/logback-silent.xml b/gremlin-groovy/src/test/resources/logback-silent.xml
new file mode 100644
index 0000000..4c5947d
--- /dev/null
+++ b/gremlin-groovy/src/test/resources/logback-silent.xml
@@ -0,0 +1,26 @@
+<!--
+Licensed to the Apache Software Foundation (ASF) under one or more
+contributor license agreements.  See the NOTICE file distributed with
+this work for additional information regarding copyright ownership.
+The ASF licenses this file to You under the Apache License, Version 2.0
+(the "License"); you may not use this file except in compliance with
+the License.  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+-->
+<configuration>
+    <appender name="stdout" class="ch.qos.logback.core.ConsoleAppender">
+        <encoder>
+            <pattern>[%p] %C - %m%n</pattern>
+        </encoder>
+    </appender>
+    <root level="OFF">
+        <appender-ref ref="stdout"/>
+    </root>
+</configuration>
\ No newline at end of file
diff --git a/gremlin-groovy/src/test/resources/logback-test.xml b/gremlin-groovy/src/test/resources/logback-test.xml
new file mode 100644
index 0000000..5d94c3b
--- /dev/null
+++ b/gremlin-groovy/src/test/resources/logback-test.xml
@@ -0,0 +1,26 @@
+<!--
+Licensed to the Apache Software Foundation (ASF) under one or more
+contributor license agreements.  See the NOTICE file distributed with
+this work for additional information regarding copyright ownership.
+The ASF licenses this file to You under the Apache License, Version 2.0
+(the "License"); you may not use this file except in compliance with
+the License.  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+-->
+<configuration>
+    <appender name="stdout" class="ch.qos.logback.core.ConsoleAppender">
+        <encoder>
+            <pattern>[%p] %C - %m%n</pattern>
+        </encoder>
+    </appender>
+    <root level="WARN">
+        <appender-ref ref="stdout"/>
+    </root>
+</configuration>
\ No newline at end of file
diff --git a/gremlin-javascript/pom.xml b/gremlin-javascript/pom.xml
index 4f2c284..53423bf 100644
--- a/gremlin-javascript/pom.xml
+++ b/gremlin-javascript/pom.xml
@@ -65,9 +65,9 @@ limitations under the License.
                         <version>${project.version}</version>
                     </dependency>
                     <dependency>
-                        <groupId>log4j</groupId>
-                        <artifactId>log4j</artifactId>
-                        <version>${log4j.version}</version>
+                        <groupId>ch.qos.logback</groupId>
+                        <artifactId>logback-classic</artifactId>
+                        <version>${logback.version}</version>
                         <scope>runtime</scope>
                     </dependency>
                     <dependency>
diff --git a/gremlin-javascript/src/main/javascript/gremlin-javascript/package.json b/gremlin-javascript/src/main/javascript/gremlin-javascript/package.json
index 7dca6a7..0986639 100644
--- a/gremlin-javascript/src/main/javascript/gremlin-javascript/package.json
+++ b/gremlin-javascript/src/main/javascript/gremlin-javascript/package.json
@@ -40,4 +40,4 @@
   "engines": {
     "node": ">=10"
   }
-}
\ No newline at end of file
+}
diff --git a/gremlin-python/pom.xml b/gremlin-python/pom.xml
index 23e743e..6ba8f10 100644
--- a/gremlin-python/pom.xml
+++ b/gremlin-python/pom.xml
@@ -259,9 +259,9 @@ limitations under the License.
                                 <scope>runtime</scope>
                             </dependency>
                             <dependency>
-                                <groupId>log4j</groupId>
-                                <artifactId>log4j</artifactId>
-                                <version>${log4j.version}</version>
+                                <groupId>ch.qos.logback</groupId>
+                                <artifactId>logback-classic</artifactId>
+                                <version>${logback.version}</version>
                                 <scope>runtime</scope>
                             </dependency>
                         </dependencies>
diff --git a/gremlin-server/conf/log4j-server.properties b/gremlin-server/conf/log4j-server.properties
deleted file mode 100644
index 8bf809c..0000000
--- a/gremlin-server/conf/log4j-server.properties
+++ /dev/null
@@ -1,32 +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.
-
-log4j.rootLogger=INFO, stdout
-log4j.appender.stdout=org.apache.log4j.ConsoleAppender
-log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
-log4j.appender.stdout.layout.ConversionPattern=[%p] %C{1} - %m%n
-
-log4j.logger.org.apache.tinkerpop.gremlin.driver.Connection=OFF
-log4j.logger.org.apache.tinkerpop.gremlin.driver.ConnectionPool=OFF
-log4j.logger.org.apache.tinkerpop.gremlin.neo4j.structure.Neo4jGraph=ERROR
-log4j.logger.org.apache.hadoop.mapred.JobClient=INFO
-log4j.logger.org.apache.hadoop.mapreduce.Job=INFO
-log4j.logger.org.apache.tinkerpop.gremlin.hadoop.process.computer.mapreduce.MapReduceGraphComputer=INFO
-log4j.logger.org.apache.tinkerpop.gremlin.hadoop.structure.HadoopGraph=INFO
-log4j.logger.org.apache.tinkerpop.gremlin.spark.process.computer.SparkGraphComputer=INFO
-log4j.logger.org.apache.spark.metrics.MetricsSystem=ERROR
-log4j.logger.com.jcabi.manifests.Manifests=OFF
diff --git a/gremlin-server/conf/logback.xml b/gremlin-server/conf/logback.xml
new file mode 100644
index 0000000..d2831fa
--- /dev/null
+++ b/gremlin-server/conf/logback.xml
@@ -0,0 +1,20 @@
+<configuration>
+    <appender name="stdout" class="ch.qos.logback.core.ConsoleAppender">
+        <encoder>
+            <pattern>[%p] %C{1} - %m%n</pattern>
+        </encoder>
+    </appender>
+    <logger name="org.apache.tinkerpop.gremlin.hadoop.structure.HadoopGraph" level="INFO"/>
+    <logger name="org.apache.tinkerpop.gremlin.hadoop.process.computer.mapreduce.MapReduceGraphComputer" level="INFO"/>
+    <logger name="org.apache.hadoop.mapreduce.Job" level="INFO"/>
+    <logger name="org.apache.tinkerpop.gremlin.neo4j.structure.Neo4jGraph" level="ERROR"/>
+    <logger name="org.apache.spark.metrics.MetricsSystem" level="ERROR"/>
+    <logger name="org.apache.tinkerpop.gremlin.spark.process.computer.SparkGraphComputer" level="INFO"/>
+    <logger name="org.apache.hadoop.mapred.JobClient" level="INFO"/>
+    <logger name="org.apache.tinkerpop.gremlin.driver.Connection" level="OFF"/>
+    <logger name="org.apache.tinkerpop.gremlin.driver.ConnectionPool" level="OFF"/>
+    <logger name="com.jcabi.manifests.Manifests" level="OFF"/>
+    <root level="INFO">
+        <appender-ref ref="stdout"/>
+    </root>
+</configuration>
\ No newline at end of file
diff --git a/gremlin-server/pom.xml b/gremlin-server/pom.xml
index 3190c58..b971cb3 100644
--- a/gremlin-server/pom.xml
+++ b/gremlin-server/pom.xml
@@ -46,13 +46,8 @@ limitations under the License.
             <artifactId>commons-collections</artifactId>
         </dependency>
         <dependency>
-            <groupId>org.slf4j</groupId>
-            <artifactId>slf4j-log4j12</artifactId>
-            <optional>true</optional>
-        </dependency>
-        <dependency>
-            <groupId>log4j</groupId>
-            <artifactId>log4j</artifactId>
+            <groupId>ch.qos.logback</groupId>
+            <artifactId>logback-classic</artifactId>
             <optional>true</optional>
         </dependency>
         <!-- METRICS -->
@@ -100,6 +95,11 @@ limitations under the License.
             <version>${project.version}</version>
             <scope>test</scope>
         </dependency>
+        <dependency>
+            <groupId>io.github.hakky54</groupId>
+            <artifactId>logcaptor</artifactId>
+            <scope>test</scope>
+        </dependency>
     </dependencies>
     <build>
         <directory>${basedir}/target</directory>
diff --git a/gremlin-server/src/main/bin/gremlin-server.bat b/gremlin-server/src/main/bin/gremlin-server.bat
index 73df2a3..8b94c9c 100644
--- a/gremlin-server/src/main/bin/gremlin-server.bat
+++ b/gremlin-server/src/main/bin/gremlin-server.bat
@@ -41,7 +41,7 @@ if "%1" == "install" goto install
 :server
 
 :: Launch the application
-java -Dlog4j.configuration=conf/log4j-server.properties %JAVA_OPTIONS% %JAVA_ARGS% -cp "%LIBDIR%/*;%EXTDIR%;" org.apache.tinkerpop.gremlin.server.GremlinServer %*
+java -Dlogback.configurationFile=conf/log4back.xml %JAVA_OPTIONS% %JAVA_ARGS% -cp "%LIBDIR%/*;%EXTDIR%;" org.apache.tinkerpop.gremlin.server.GremlinServer %*
 
 :install
 
@@ -55,4 +55,4 @@ goto loop1
 
 :after_loop
 
-java -Dlog4j.configuration=conf/log4j-server.properties %JAVA_OPTIONS% %JAVA_ARGS% -cp "%LIBDIR%/*;%EXTDIR%;" org.apache.tinkerpop.gremlin.server.util.GremlinServerInstall %RESTVAR%
+java -Dlogback.configurationFile=conf/log4back.xml %JAVA_OPTIONS% %JAVA_ARGS% -cp "%LIBDIR%/*;%EXTDIR%;" org.apache.tinkerpop.gremlin.server.util.GremlinServerInstall %RESTVAR%
diff --git a/gremlin-server/src/main/bin/gremlin-server.sh b/gremlin-server/src/main/bin/gremlin-server.sh
index c114c64..41e446b 100755
--- a/gremlin-server/src/main/bin/gremlin-server.sh
+++ b/gremlin-server/src/main/bin/gremlin-server.sh
@@ -80,7 +80,7 @@ if [[ ! -r "$GREMLIN_YAML" ]]; then
 fi
 
 # absolute file path requires 'file:'
-LOG4J_CONF="file:$GREMLIN_HOME/conf/log4j-server.properties"
+LOGBACK_CONF="file:$GREMLIN_HOME/conf/logback.xml"
 
 # Find Java
 if [[ "$JAVA_HOME" = "" ]] ; then
@@ -166,7 +166,7 @@ start() {
       exit 1
     fi
 
-    $JAVA -Dlog4j.configuration=$LOG4J_CONF $JAVA_OPTIONS -cp $CLASSPATH $GREMLIN_SERVER_CMD "$GREMLIN_YAML" >> "$LOG_FILE" 2>&1 &
+    $JAVA -Dlogback.configurationFile=$LOGBACK_CONF $JAVA_OPTIONS -cp $CLASSPATH $GREMLIN_SERVER_CMD "$GREMLIN_YAML" >> "$LOG_FILE" 2>&1 &
     PID=$!
     disown $PID
     echo $PID > "$PID_FILE"
@@ -184,7 +184,7 @@ start() {
       exit 1
     fi
 
-    su -c "$JAVA -Dlog4j.configuration=$LOG4J_CONF $JAVA_OPTIONS -cp $CLASSPATH $GREMLIN_SERVER_CMD \"$GREMLIN_YAML\" >> \"$LOG_FILE\" 2>&1 & echo \$! "  "$RUNAS" > "$PID_FILE"
+    su -c "$JAVA -Dlogback.configurationFile=$LOGBACK_CONF $JAVA_OPTIONS -cp $CLASSPATH $GREMLIN_SERVER_CMD \"$GREMLIN_YAML\" >> \"$LOG_FILE\" 2>&1 & echo \$! "  "$RUNAS" > "$PID_FILE"
     chown "$RUNAS" "$PID_FILE"
   fi
 
@@ -209,7 +209,7 @@ startForeground() {
   fi
 
   if [[ -z "$RUNAS" ]]; then
-    $JAVA -Dlog4j.configuration=$LOG4J_CONF $JAVA_OPTIONS -cp $CLASSPATH $GREMLIN_SERVER_CMD "$GREMLIN_YAML"
+    $JAVA -Dlogback.configurationFile=$LOGBACK_CONF $JAVA_OPTIONS -cp $CLASSPATH $GREMLIN_SERVER_CMD "$GREMLIN_YAML"
     exit 0
   else
     echo Starting in foreground not supported with RUNAS
@@ -231,9 +231,9 @@ install() {
 
   DEPS="$@"
   if [[ -z "$RUNAS" ]]; then
-    $JAVA -Dlog4j.configuration=$LOG4J_CONF $JAVA_OPTIONS -cp $CLASSPATH $GREMLIN_INSTALL_CMD $DEPS
+    $JAVA -Dlogback.configurationFile=$LOGBACK_CONF $JAVA_OPTIONS -cp $CLASSPATH $GREMLIN_INSTALL_CMD $DEPS
   else
-    su -c "$JAVA -Dlog4j.configuration=$LOG4J_CONF $JAVA_OPTIONS -cp $CLASSPATH $GREMLIN_INSTALL_CMD $DEPS "  "$RUNAS"
+    su -c "$JAVA -Dlogback.configurationFile=$LOGBACK_CONF $JAVA_OPTIONS -cp $CLASSPATH $GREMLIN_INSTALL_CMD $DEPS "  "$RUNAS"
   fi
 
 }
diff --git a/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/GremlinServer.java b/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/GremlinServer.java
index d022ffb..2cec205 100644
--- a/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/GremlinServer.java
+++ b/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/GremlinServer.java
@@ -339,7 +339,7 @@ public class GremlinServer {
     }
 
     public static void main(final String[] args) throws Exception {
-        // add to vm options: -Dlog4j.configuration=file:conf/log4j.properties
+        // add to vm options: -Dlogback.configurationFile=file:conf/logback.xml
         printHeader();
         final String file;
         if (args.length > 0)
diff --git a/gremlin-server/src/main/static/LICENSE b/gremlin-server/src/main/static/LICENSE
index f3da4f7..02b8fe9 100644
--- a/gremlin-server/src/main/static/LICENSE
+++ b/gremlin-server/src/main/static/LICENSE
@@ -225,7 +225,6 @@ The Apache TinkerPop project bundles the following components under the MIT Lice
 
      JCL 1.1.1 implemented over SLF4J (org.slf4j:jcl-over-slf4j:1.7.25 - http://www.slf4j.org) - for details, see licenses/slf4j
      SLF4J API Module (org.slf4j:slf4j-api:1.7.25 - http://www.slf4j.org) - for details, see licenses/slf4j
-     SLF4J LOG4J-12 Binding (org.slf4j:slf4j-log4j12:1.7.25 - http://www.slf4j.org) - for details, see licenses/slf4j
      Foundation stylesheet for CodeRay (http://foundation.zurb.com) - for details, see licenses/foundation
      normalize.css 2.1.2 (http://necolas.github.io/normalize.css/) - for details, see licenses/normalize
 
@@ -236,3 +235,8 @@ Other Licenses
 The Apache TinkerPop project bundles the following components under the ISC License:
 
      jBCrypt (org.mindrot:jbcrypt:0.4 - https://github.com/djmdjm/jBCrypt) - for details, see licenses/jbcrypt
+
+The Apache TinkerPop project bundles the following components under the Eclipse Public License 1.0:
+
+     logback-core (ch.qos.logback:logback-core:1.2.3 - https://logback.qos.ch) - for details, see licenses/logback
+     logback-classic (ch.qos.logback:logback-classic:1.2.3 - https://logback.qos.ch) - for details, see licenses/logback
\ No newline at end of file
diff --git a/gremlin-server/src/main/static/licenses/logback b/gremlin-server/src/main/static/licenses/logback
new file mode 100644
index 0000000..8953762
--- /dev/null
+++ b/gremlin-server/src/main/static/licenses/logback
@@ -0,0 +1,14 @@
+Logback LICENSE
+---------------
+
+Logback: the reliable, generic, fast and flexible logging framework.
+Copyright (C) 1999-2015, QOS.ch. All rights reserved.
+
+This program and the accompanying materials are dual-licensed under
+either the terms of the Eclipse Public License v1.0 as published by
+the Eclipse Foundation
+
+  or (per the licensee's choosing)
+
+under the terms of the GNU Lesser General Public License version 2.1
+as published by the Free Software Foundation.
\ No newline at end of file
diff --git a/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/driver/ClientConnectionIntegrateTest.java b/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/driver/ClientConnectionIntegrateTest.java
index 962cfc2..ffc12e0 100644
--- a/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/driver/ClientConnectionIntegrateTest.java
+++ b/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/driver/ClientConnectionIntegrateTest.java
@@ -18,16 +18,20 @@
  */
 package org.apache.tinkerpop.gremlin.driver;
 
+import ch.qos.logback.classic.Level;
+import ch.qos.logback.classic.Logger;
 import io.netty.handler.codec.CorruptedFrameException;
-import org.apache.log4j.Level;
-import org.apache.log4j.Logger;
+import nl.altindag.log.LogCaptor;
 import org.apache.tinkerpop.gremlin.driver.ser.Serializers;
 import org.apache.tinkerpop.gremlin.server.AbstractGremlinServerIntegrationTest;
 import org.apache.tinkerpop.gremlin.server.TestClientFactory;
-import org.apache.tinkerpop.gremlin.util.Log4jRecordingAppender;
+import org.hamcrest.core.Is;
 import org.junit.After;
+import org.junit.AfterClass;
 import org.junit.Before;
+import org.junit.BeforeClass;
 import org.junit.Test;
+import org.slf4j.LoggerFactory;
 
 import static org.hamcrest.CoreMatchers.is;
 import static org.hamcrest.MatcherAssert.assertThat;
@@ -35,33 +39,33 @@ import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.fail;
 
 public class ClientConnectionIntegrateTest extends AbstractGremlinServerIntegrationTest {
-    private Log4jRecordingAppender recordingAppender = null;
-    private Level previousLogLevel;
 
-    @Before
-    public void setupForEachTest() {
-        recordingAppender = new Log4jRecordingAppender();
-        final Logger rootLogger = Logger.getRootLogger();
+    private static LogCaptor logCaptor;
+    private Level previousLevel;
 
-        if (name.getMethodName().equals("shouldCloseConnectionDeadDueToUnRecoverableError")) {
-            final org.apache.log4j.Logger connectionLogger = org.apache.log4j.Logger.getLogger(Connection.class);
-            previousLogLevel = connectionLogger.getLevel();
-            connectionLogger.setLevel(Level.DEBUG);
-        }
+    @BeforeClass
+    public static void setupLogCaptor() {
+        logCaptor = LogCaptor.forClass(Connection.class);
+    }
 
-        rootLogger.addAppender(recordingAppender);
+    @AfterClass
+    public static void tearDownAfterClass() {
+        logCaptor.close();
     }
 
-    @After
-    public void teardownForEachTest() {
-        final Logger rootLogger = Logger.getRootLogger();
+    @Before
+    public void setupForEachTest() {
+        final Logger lc = (Logger) LoggerFactory.getLogger(Connection.class);
+        previousLevel = lc.getLevel();
+        lc.setLevel(Level.DEBUG);
 
-        if (name.getMethodName().equals("shouldCloseConnectionDeadDueToUnRecoverableError")) {
-            final org.apache.log4j.Logger connectionLogger = org.apache.log4j.Logger.getLogger(Connection.class);
-            connectionLogger.setLevel(previousLogLevel);
-        }
+        logCaptor.clearLogs();
+    }
 
-        rootLogger.removeAppender(recordingAppender);
+    @After
+    public void afterEachTest() {
+        final Logger lc = (Logger) LoggerFactory.getLogger(Connection.class);
+        lc.setLevel(previousLevel);
     }
 
     /**
@@ -106,7 +110,8 @@ public class ClientConnectionIntegrateTest extends AbstractGremlinServerIntegrat
 
         // Assert that the connection has been destroyed. Specifically check for the string with
         // isDead=true indicating the connection that was closed due to CorruptedFrameException.
-        assertThat(recordingAppender.logContainsAny("^(?!.*(isDead=false)).*isDead=true.*destroyed successfully.$"), is(true));
+        assertThat(logCaptor.getLogs().stream().anyMatch(m -> m.matches(
+                "^(?!.*(isDead=false)).*isDead=true.*destroyed successfully.$")), Is.is(true));
 
     }
 }
diff --git a/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/ContextTest.java b/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/ContextTest.java
index c7ff19f..56cb718 100644
--- a/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/ContextTest.java
+++ b/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/ContextTest.java
@@ -19,15 +19,14 @@
 package org.apache.tinkerpop.gremlin.server;
 
 import io.netty.channel.ChannelHandlerContext;
-import org.apache.log4j.Level;
-import org.apache.log4j.Logger;
+import nl.altindag.log.LogCaptor;
 import org.apache.tinkerpop.gremlin.driver.message.RequestMessage;
 import org.apache.tinkerpop.gremlin.driver.message.ResponseMessage;
 import org.apache.tinkerpop.gremlin.driver.message.ResponseStatusCode;
 import org.apache.tinkerpop.gremlin.server.handler.Frame;
-import org.apache.tinkerpop.gremlin.util.Log4jRecordingAppender;
-import org.junit.After;
+import org.junit.AfterClass;
 import org.junit.Before;
+import org.junit.BeforeClass;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
@@ -37,11 +36,29 @@ import java.util.Arrays;
 import java.util.UUID;
 import java.util.function.BiFunction;
 
-import static org.junit.Assert.assertTrue;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.core.Is.is;
 
 @RunWith(Parameterized.class)
 public class ContextTest {
 
+    private static LogCaptor logCaptor;
+
+    @BeforeClass
+    public static void setupLogCaptor() {
+        logCaptor = LogCaptor.forRoot();
+    }
+
+    @AfterClass
+    public static void tearDownAfterClass() {
+        logCaptor.close();
+    }
+
+    @Before
+    public void setupForEachTest() {
+        logCaptor.clearLogs();
+    }
+
     @Parameterized.Parameter(value = 0)
     public BiFunction<Context, ResponseStatusCode, Void> writeInvoker;
 
@@ -49,9 +66,6 @@ public class ContextTest {
     private final RequestMessage request = RequestMessage.build("test").create();
     private final Settings settings = new Settings();
     private final Context context = new Context(request, ctx, settings, null, null, null);
-    private final Log4jRecordingAppender recordingAppender = new Log4jRecordingAppender();
-
-    private Level originalLogLevel;
 
     @Parameterized.Parameters(name = "{0}")
     public static Iterable<Object[]> data() {
@@ -86,21 +100,6 @@ public class ContextTest {
         });
     }
 
-    @Before
-    public void addRecordingAppender() {
-        final Logger rootLogger = Logger.getRootLogger();
-        rootLogger.addAppender(recordingAppender);
-        originalLogLevel = rootLogger.getLevel();
-        rootLogger.setLevel(Level.ALL);
-    }
-
-    @After
-    public void removeRecordingAppender() {
-        final Logger rootLogger = Logger.getRootLogger();
-        rootLogger.setLevel(originalLogLevel);
-        rootLogger.removeAppender(recordingAppender);
-    }
-
     @Test
     public void shouldAllowMultipleNonFinalResponses() {
         writeInvoker.apply(context, ResponseStatusCode.AUTHENTICATE);
@@ -127,8 +126,10 @@ public class ContextTest {
         Mockito.verify(ctx, Mockito.times(2)).flush();
 
         writeInvoker.apply(context, ResponseStatusCode.SERVER_ERROR_TIMEOUT);
-        assertTrue(recordingAppender.logContainsAny(".*" + request.getRequestId() + ".*"));
-        assertTrue(recordingAppender.logContainsAny(".*" + ResponseStatusCode.SERVER_ERROR_TIMEOUT + "$"));
+        assertThat(logCaptor.getLogs().stream().anyMatch(m ->
+                m.matches(".*" + request.getRequestId() + ".*")), is(true));
+        assertThat(logCaptor.getLogs().stream().anyMatch(m ->
+                m.matches(".*" + ResponseStatusCode.SERVER_ERROR_TIMEOUT + "$")), is(true));
 
         // ensure there were no other writes to the channel
         Mockito.verify(ctx, Mockito.times(2)).write(Mockito.any());
@@ -142,8 +143,10 @@ public class ContextTest {
         Mockito.verify(ctx, Mockito.times(1)).flush();
 
         writeInvoker.apply(context, ResponseStatusCode.PARTIAL_CONTENT);
-        assertTrue(recordingAppender.logContainsAny(".*" + request.getRequestId() + ".*"));
-        assertTrue(recordingAppender.logContainsAny(".*" + ResponseStatusCode.PARTIAL_CONTENT + "$"));
+        assertThat(logCaptor.getLogs().stream().anyMatch(m ->
+                m.matches(".*" + request.getRequestId() + ".*")), is(true));
+        assertThat(logCaptor.getLogs().stream().anyMatch(m ->
+                m.matches(".*" + ResponseStatusCode.PARTIAL_CONTENT + "$")), is(true));
 
         // ensure there were no other writes to the channel
         Mockito.verify(ctx, Mockito.times(1)).write(Mockito.any());
@@ -159,8 +162,10 @@ public class ContextTest {
         Frame frame = Mockito.mock(Frame.class);
         context.writeAndFlush(ResponseStatusCode.SUCCESS, frame);
 
-        assertTrue(recordingAppender.logContainsAny(".*" + request.getRequestId() + ".*"));
-        assertTrue(recordingAppender.logContainsAny(".*" + ResponseStatusCode.SUCCESS + "$"));
+        assertThat(logCaptor.getLogs().stream().anyMatch(m ->
+                m.matches(".*" + request.getRequestId() + ".*")), is(true));
+        assertThat(logCaptor.getLogs().stream().anyMatch(m ->
+                m.matches(".*" + ResponseStatusCode.SUCCESS + "$")), is(true));
 
         // ensure there were no other writes to the channel
         Mockito.verify(ctx, Mockito.times(1)).write(Mockito.any());
diff --git a/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinDriverIntegrateTest.java b/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinDriverIntegrateTest.java
index 7a5d097..dc097b4 100644
--- a/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinDriverIntegrateTest.java
+++ b/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinDriverIntegrateTest.java
@@ -18,8 +18,10 @@
  */
 package org.apache.tinkerpop.gremlin.server;
 
+import ch.qos.logback.classic.Level;
+import ch.qos.logback.classic.Logger;
+import nl.altindag.log.LogCaptor;
 import org.apache.commons.lang3.exception.ExceptionUtils;
-import org.apache.log4j.Level;
 import org.apache.tinkerpop.gremlin.TestHelper;
 import org.apache.tinkerpop.gremlin.driver.Client;
 import org.apache.tinkerpop.gremlin.driver.Cluster;
@@ -47,18 +49,18 @@ import org.apache.tinkerpop.gremlin.structure.io.Storage;
 import org.apache.tinkerpop.gremlin.structure.util.detached.DetachedVertex;
 import org.apache.tinkerpop.gremlin.structure.util.reference.ReferenceVertex;
 import org.apache.tinkerpop.gremlin.tinkergraph.structure.TinkerFactory;
-import org.apache.tinkerpop.gremlin.util.Log4jRecordingAppender;
 import groovy.json.JsonBuilder;
 import org.apache.tinkerpop.gremlin.util.TimeUtil;
 import org.apache.tinkerpop.gremlin.util.function.FunctionUtils;
 import org.apache.tinkerpop.gremlin.util.iterator.IteratorUtils;
 import org.junit.After;
+import org.junit.AfterClass;
 import org.junit.Before;
+import org.junit.BeforeClass;
 import org.junit.Ignore;
 import org.junit.Test;
 import org.mockito.ArgumentCaptor;
 import org.mockito.Mockito;
-import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import java.awt.Color;
@@ -107,44 +109,47 @@ import static org.mockito.Mockito.verify;
  * @author Stephen Mallette (http://stephen.genoprime.com)
  */
 public class GremlinDriverIntegrateTest extends AbstractGremlinServerIntegrationTest {
-    private static final Logger logger = LoggerFactory.getLogger(GremlinDriverIntegrateTest.class);
+    private static final org.slf4j.Logger logger = LoggerFactory.getLogger(GremlinDriverIntegrateTest.class);
 
-    private Log4jRecordingAppender recordingAppender = null;
+    private static LogCaptor logCaptor;
     private Level previousLogLevel;
 
+    @BeforeClass
+    public static void setupLogCaptor() {
+        logCaptor = LogCaptor.forRoot();
+    }
+
+    @AfterClass
+    public static void tearDownAfterClass() {
+        logCaptor.close();
+    }
+
     @Before
     public void setupForEachTest() {
-        recordingAppender = new Log4jRecordingAppender();
-        final org.apache.log4j.Logger rootLogger = org.apache.log4j.Logger.getRootLogger();
-
         if (name.getMethodName().equals("shouldKeepAliveForWebSockets") ||
                 name.getMethodName().equals("shouldKeepAliveForWebSocketsWithNoInFlightRequests")) {
-            final org.apache.log4j.Logger webSocketClientHandlerLogger = org.apache.log4j.Logger.getLogger(WebSocketClientHandler.class);
+            final Logger webSocketClientHandlerLogger = (Logger) LoggerFactory.getLogger(WebSocketClientHandler.class);
             previousLogLevel = webSocketClientHandlerLogger.getLevel();
             webSocketClientHandlerLogger.setLevel(Level.DEBUG);
         } else if (name.getMethodName().equals("shouldEventuallySucceedAfterMuchFailure")) {
-            final org.apache.log4j.Logger opExecutorHandlerLogger = org.apache.log4j.Logger.getLogger(OpExecutorHandler.class);
+            final Logger opExecutorHandlerLogger = (Logger) LoggerFactory.getLogger(OpExecutorHandler.class);
             previousLogLevel = opExecutorHandlerLogger.getLevel();
             opExecutorHandlerLogger.setLevel(Level.ERROR);
         }
 
-        rootLogger.addAppender(recordingAppender);
+        logCaptor.clearLogs();
     }
 
     @After
-    public void teardownForEachTest() {
-        final org.apache.log4j.Logger rootLogger = org.apache.log4j.Logger.getRootLogger();
-
+    public void afterEachTest() {
         if (name.getMethodName().equals("shouldKeepAliveForWebSockets") ||
                 name.getMethodName().equals("shouldKeepAliveForWebSocketsWithNoInFlightRequests")) {
-            final org.apache.log4j.Logger webSocketClientHandlerLogger = org.apache.log4j.Logger.getLogger(WebSocketClientHandler.class);
+            final Logger webSocketClientHandlerLogger = (Logger) LoggerFactory.getLogger(WebSocketClientHandler.class);
             webSocketClientHandlerLogger.setLevel(previousLogLevel);
         } else if (name.getMethodName().equals("shouldEventuallySucceedAfterMuchFailure")) {
-            final org.apache.log4j.Logger opExecutorHandlerLogger = org.apache.log4j.Logger.getLogger(OpExecutorHandler.class);
+            final Logger opExecutorHandlerLogger = (Logger) LoggerFactory.getLogger(OpExecutorHandler.class);
             opExecutorHandlerLogger.setLevel(previousLogLevel);
         }
-
-        rootLogger.removeAppender(recordingAppender);
     }
 
     /**
@@ -310,7 +315,7 @@ public class GremlinDriverIntegrateTest extends AbstractGremlinServerIntegration
             }
 
             // there really shouldn't be more than 3 of these sent. should definitely be at least one though
-            final long messages = recordingAppender.getMessages().stream().filter(m -> m.contains("Sending ping frame to the server")).count();
+            final long messages = logCaptor.getLogs().stream().filter(m -> m.contains("Sending ping frame to the server")).count();
             assertThat(messages, allOf(greaterThan(0L), lessThanOrEqualTo(3L)));
         } finally {
             cluster.close();
@@ -341,7 +346,7 @@ public class GremlinDriverIntegrateTest extends AbstractGremlinServerIntegration
             }
 
             // there really shouldn't be more than 3 of these sent. should definitely be at least one though
-            final long messages = recordingAppender.getMessages().stream().filter(m -> m.contains("Sending ping frame to the server")).count();
+            final long messages = logCaptor.getLogs().stream().filter(m -> m.contains("Sending ping frame to the server")).count();
             assertThat(messages, allOf(greaterThan(0L), lessThanOrEqualTo(3L)));
         } finally {
             cluster.close();
diff --git a/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinServerAuditLogDeprecatedIntegrateTest.java b/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinServerAuditLogDeprecatedIntegrateTest.java
index b337991..d459926 100644
--- a/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinServerAuditLogDeprecatedIntegrateTest.java
+++ b/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinServerAuditLogDeprecatedIntegrateTest.java
@@ -18,13 +18,12 @@
  */
 package org.apache.tinkerpop.gremlin.server;
 
+import nl.altindag.log.LogCaptor;
 import org.apache.http.client.methods.CloseableHttpResponse;
 import org.apache.http.client.methods.HttpGet;
 import org.apache.http.impl.client.CloseableHttpClient;
 import org.apache.http.impl.client.HttpClients;
 import org.apache.http.util.EntityUtils;
-import org.apache.log4j.Logger;
-import org.apache.log4j.spi.LoggingEvent;
 import org.apache.tinkerpop.gremlin.driver.Client;
 import org.apache.tinkerpop.gremlin.driver.Cluster;
 import org.apache.tinkerpop.gremlin.driver.remote.DriverRemoteConnection;
@@ -36,20 +35,19 @@ import org.apache.tinkerpop.gremlin.server.auth.SimpleAuthenticator;
 import org.apache.tinkerpop.gremlin.server.channel.HttpChannelizer;
 import org.apache.tinkerpop.gremlin.server.handler.SaslAndHttpBasicAuthenticationHandler;
 import org.apache.tinkerpop.gremlin.structure.io.graphson.GraphSONTokens;
-import org.apache.tinkerpop.gremlin.util.Log4jRecordingAppender;
 import org.apache.tinkerpop.shaded.jackson.databind.JsonNode;
 import org.apache.tinkerpop.shaded.jackson.databind.ObjectMapper;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
 import org.junit.Test;
+import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import java.util.Base64;
 import java.util.HashMap;
-import java.util.List;
 import java.util.Map;
-import java.util.stream.Stream;
 
-import static org.apache.log4j.Level.INFO;
-import static org.apache.tinkerpop.gremlin.server.GremlinServer.AUDIT_LOGGER_NAME;
 import static org.apache.tinkerpop.gremlin.server.GremlinServerAuthKrb5IntegrateTest.TESTCONSOLE;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
@@ -62,8 +60,7 @@ import static org.junit.Assert.assertTrue;
  * @author Marc de Lignie
  */
 public class GremlinServerAuditLogDeprecatedIntegrateTest extends AbstractGremlinServerIntegrationTest {
-    private static final org.slf4j.Logger logger = LoggerFactory.getLogger(GremlinServerAuditLogDeprecatedIntegrateTest.class);
-    private Log4jRecordingAppender recordingAppender = null;
+    private static final Logger logger = LoggerFactory.getLogger(GremlinServerAuditLogDeprecatedIntegrateTest.class);
 
     private final ObjectMapper mapper = new ObjectMapper();
     private final Base64.Encoder encoder = Base64.getUrlEncoder();
@@ -74,12 +71,25 @@ public class GremlinServerAuditLogDeprecatedIntegrateTest extends AbstractGremli
 
     private KdcFixture kdcServer;
 
+    private static LogCaptor logCaptor;
+
+    @BeforeClass
+    public static void setupLogCaptor() {
+        logCaptor = LogCaptor.forRoot();
+    }
+
+    @AfterClass
+    public static void tearDownAfterClass() {
+        logCaptor.close();
+    }
+
+    @Before
+    public void setupForEachTest() {
+        logCaptor.clearLogs();
+    }
+
     @Override
     public void setUp() throws Exception {
-        recordingAppender = new Log4jRecordingAppender();
-        final Logger rootLogger = Logger.getRootLogger();
-        rootLogger.addAppender(recordingAppender);
-
         try {
             final String moduleBaseDir = System.getProperty("basedir", ".");
             final String authConfigName = moduleBaseDir + "/src/test/resources/org/apache/tinkerpop/gremlin/server/gremlin-console-jaas.conf";
@@ -94,8 +104,6 @@ public class GremlinServerAuditLogDeprecatedIntegrateTest extends AbstractGremli
 
     @Override
     public void tearDown() throws Exception {
-        final Logger rootLogger = Logger.getRootLogger();
-        rootLogger.removeAppender(recordingAppender);
         kdcServer.close();
         System.clearProperty("java.security.auth.login.config");
         super.tearDown();
@@ -165,9 +173,12 @@ public class GremlinServerAuditLogDeprecatedIntegrateTest extends AbstractGremli
 
         // WebSocketChannelizer does not add SaslAuthenticationHandler for AllowAllAuthenticator,
         // so no authenticated user log line available
-        assertTrue(recordingAppender.logMatchesAny(AUDIT_LOGGER_NAME, INFO, "User with address .+? requested: 1\\+1"));
-        assertTrue(recordingAppender.logMatchesAny(AUDIT_LOGGER_NAME, INFO, "User with address .+? requested: 1\\+2"));
-        assertTrue(recordingAppender.logMatchesAny(AUDIT_LOGGER_NAME, INFO, "User with address .+? requested: 1\\+3"));
+        assertTrue(logCaptor.getLogs().stream().anyMatch(m -> m.matches(
+                "User with address .+? requested: 1\\+1")));
+        assertTrue(logCaptor.getLogs().stream().anyMatch(m -> m.matches(
+                "User with address .+? requested: 1\\+2")));
+        assertTrue(logCaptor.getLogs().stream().anyMatch(m -> m.matches(
+                "User with address .+? requested: 1\\+3")));
     }
 
     @Test
@@ -192,20 +203,14 @@ public class GremlinServerAuditLogDeprecatedIntegrateTest extends AbstractGremli
         Thread.sleep(1000);
 
         final String simpleAuthenticatorName = SimpleAuthenticator.class.getSimpleName();
-
-        final List<LoggingEvent> log = recordingAppender.getEvents();
-        final Stream<LoggingEvent> auditEvents = log.stream().filter(event -> event.getLoggerName().equals(AUDIT_LOGGER_NAME));
-        final LoggingEvent authEvent = auditEvents
-                .filter(event -> event.getMessage().toString().contains(simpleAuthenticatorName)).iterator().next();
-        final String authMsg = authEvent.getMessage().toString();
-        assertTrue(authEvent.getLevel() == INFO &&
-                authMsg.matches(String.format("User %s with address .+? authenticated by %s", username, simpleAuthenticatorName)));
-        assertTrue(log.stream().anyMatch(item -> item.getLevel() == INFO &&
-                item.getMessage().toString().matches("User with address .+? requested: 1\\+1")));
-        assertTrue(log.stream().anyMatch(item -> item.getLevel() == INFO &&
-                item.getMessage().toString().matches("User with address .+? requested: 1\\+2")));
-        assertTrue(log.stream().anyMatch(item -> item.getLevel() == INFO &&
-                item.getMessage().toString().matches("User with address .+? requested: 1\\+3")));
+        assertTrue(logCaptor.getLogs().stream().anyMatch(m -> m.matches(
+                String.format("User %s with address .+? authenticated by %s", username, simpleAuthenticatorName))));
+        assertTrue(logCaptor.getLogs().stream().anyMatch(m -> m.matches(
+                "User with address .+? requested: 1\\+1")));
+        assertTrue(logCaptor.getLogs().stream().anyMatch(m -> m.matches(
+                "User with address .+? requested: 1\\+2")));
+        assertTrue(logCaptor.getLogs().stream().anyMatch(m -> m.matches(
+                "User with address .+? requested: 1\\+3")));
     }
 
     @Test
@@ -225,19 +230,15 @@ public class GremlinServerAuditLogDeprecatedIntegrateTest extends AbstractGremli
         stopServer();
         Thread.sleep(1000);
 
-        final List<LoggingEvent> log = recordingAppender.getEvents();
-        final Stream<LoggingEvent> auditEvents = log.stream().filter(event -> event.getLoggerName().equals(AUDIT_LOGGER_NAME));
-        final LoggingEvent authEvent = auditEvents
-                .filter(event -> event.getMessage().toString().contains("Krb5Authenticator")).iterator().next();
-        final String authMsg = authEvent.getMessage().toString();
-        assertTrue(authEvent.getLevel() == INFO &&
-                authMsg.matches(String.format("User %s with address .+? authenticated by Krb5Authenticator", kdcServer.clientPrincipalName)));
-        assertTrue(log.stream().anyMatch(item -> item.getLevel() == INFO &&
-                item.getMessage().toString().matches("User with address .+? requested: 1\\+1")));
-        assertTrue(log.stream().anyMatch(item -> item.getLevel() == INFO &&
-                item.getMessage().toString().matches("User with address .+? requested: 1\\+2")));
-        assertTrue(log.stream().anyMatch(item -> item.getLevel() == INFO &&
-                item.getMessage().toString().matches("User with address .+? requested: 1\\+3")));
+        final String authenticatorName = Krb5Authenticator.class.getSimpleName();
+        assertTrue(logCaptor.getLogs().stream().anyMatch(m -> m.matches(
+                String.format("User %s with address .+? authenticated by %s", kdcServer.clientPrincipalName, authenticatorName))));
+        assertTrue(logCaptor.getLogs().stream().anyMatch(m -> m.matches(
+                "User with address .+? requested: 1\\+1")));
+        assertTrue(logCaptor.getLogs().stream().anyMatch(m -> m.matches(
+                "User with address .+? requested: 1\\+2")));
+        assertTrue(logCaptor.getLogs().stream().anyMatch(m -> m.matches(
+                "User with address .+? requested: 1\\+3")));
     }
 
     @Test
@@ -257,15 +258,15 @@ public class GremlinServerAuditLogDeprecatedIntegrateTest extends AbstractGremli
         stopServer();
         Thread.sleep(1000);
 
-        final List<LoggingEvent> log = recordingAppender.getEvents();
-        assertFalse(log.stream().anyMatch(item -> item.getLevel() == INFO &&
-                item.getMessage().toString().matches("User drankye with address .+? authenticated by Krb5Authenticator")));
-        assertFalse(log.stream().anyMatch(item -> item.getLevel() == INFO &&
-                item.getMessage().toString().matches("User with address .+? requested: 1\\+1")));
-        assertFalse(log.stream().anyMatch(item -> item.getLevel() == INFO &&
-                item.getMessage().toString().matches("User with address .+? requested: 1\\+2")));
-        assertFalse(log.stream().anyMatch(item -> item.getLevel() == INFO &&
-            item.getMessage().toString().matches("User with address .+? requested: 1\\+3")));
+        final String authenticatorName = Krb5Authenticator.class.getSimpleName();
+        assertFalse(logCaptor.getLogs().stream().anyMatch(m -> m.matches(
+                String.format("User %s with address .+? authenticated by %s", kdcServer.clientPrincipalName, authenticatorName))));
+        assertFalse(logCaptor.getLogs().stream().anyMatch(m -> m.matches(
+                "User with address .+? requested: 1\\+1")));
+        assertFalse(logCaptor.getLogs().stream().anyMatch(m -> m.matches(
+                "User with address .+? requested: 1\\+2")));
+        assertFalse(logCaptor.getLogs().stream().anyMatch(m -> m.matches(
+                "User with address .+? requested: 1\\+3")));
     }
 
     @Test
@@ -286,17 +287,11 @@ public class GremlinServerAuditLogDeprecatedIntegrateTest extends AbstractGremli
         stopServer();
         Thread.sleep(1000);
 
-        final String simpleAuthenticatorName = SimpleAuthenticator.class.getSimpleName();
-
-        final List<LoggingEvent> log = recordingAppender.getEvents();
-        final Stream<LoggingEvent> auditEvents = log.stream().filter(event -> event.getLoggerName().equals(AUDIT_LOGGER_NAME));
-        final LoggingEvent authEvent = auditEvents
-                .filter(event -> event.getMessage().toString().contains(simpleAuthenticatorName)).iterator().next();
-        final String authMsg = authEvent.getMessage().toString();
-        assertTrue(authEvent.getLevel() == INFO &&
-                authMsg.matches(String.format("User stephen with address .+? authenticated by %s", simpleAuthenticatorName)));
-        assertTrue(log.stream().anyMatch(item -> item.getLevel() == INFO &&
-                item.getMessage().toString().matches("User with address .+? requested: 1-1")));
+        final String authenticatorName = SimpleAuthenticator.class.getSimpleName();
+        assertTrue(logCaptor.getLogs().stream().anyMatch(m -> m.matches(
+                String.format("User stephen with address .+? authenticated by %s", authenticatorName))));
+        assertTrue(logCaptor.getLogs().stream().anyMatch(m -> m.matches(
+                "User with address .+? requested: 1-1")));
     }
 
     @Test
@@ -318,17 +313,11 @@ public class GremlinServerAuditLogDeprecatedIntegrateTest extends AbstractGremli
         stopServer();
         Thread.sleep(1000);
 
-        final String simpleAuthenticatorName = SimpleAuthenticator.class.getSimpleName();
-
-        final List<LoggingEvent> log = recordingAppender.getEvents();
-        final Stream<LoggingEvent> auditEvents = log.stream().filter(event -> event.getLoggerName().equals(AUDIT_LOGGER_NAME));
-        final LoggingEvent authEvent = auditEvents
-                .filter(event -> event.getMessage().toString().contains(simpleAuthenticatorName)).iterator().next();
-        final String authMsg = authEvent.getMessage().toString();
-        assertTrue(authEvent.getLevel() == INFO &&
-                authMsg.matches(String.format("User %s with address .+? authenticated by %s", username, simpleAuthenticatorName)));
-        assertTrue(log.stream().anyMatch(item -> item.getLevel() == INFO &&
-                item.getMessage().toString().matches("User with address .+? requested: \\[\\[], \\[V\\(\\), count\\(\\)]]")));
+        final String authenticatorName = SimpleAuthenticator.class.getSimpleName();
+        assertTrue(logCaptor.getLogs().stream().anyMatch(m -> m.matches(
+                String.format("User %s with address .+? authenticated by %s", username, authenticatorName))));
+        assertTrue(logCaptor.getLogs().stream().anyMatch(m ->
+                m.matches("User with address .+? requested: \\[\\[], \\[V\\(\\), count\\(\\)]]")));
     }
 
     @Test
@@ -360,27 +349,23 @@ public class GremlinServerAuditLogDeprecatedIntegrateTest extends AbstractGremli
         stopServer();
         Thread.sleep(1000);
 
-        final List<LoggingEvent> log = recordingAppender.getEvents();
-        final Stream<LoggingEvent> auditEvents = log.stream().filter(event -> event.getLoggerName().equals(AUDIT_LOGGER_NAME));
-        final LoggingEvent authEvent = auditEvents
-                .filter(event -> event.getMessage().toString().contains("Krb5Authenticator")).iterator().next();
-        final String authMsg = authEvent.getMessage().toString();
-        assertTrue(authEvent.getLevel() == INFO &&
-                authMsg.matches(String.format("User %s with address .+? authenticated by Krb5Authenticator", kdcServer.clientPrincipalName)));
-        assertTrue(log.stream().anyMatch(item -> item.getLevel() == INFO &&
-                item.getMessage().toString().matches("User with address .+? requested: 1\\+1")));
-        assertTrue(log.stream().anyMatch(item -> item.getLevel() == INFO &&
-                item.getMessage().toString().matches("User with address .+? requested: 1\\+2")));
-        assertTrue(log.stream().anyMatch(item -> item.getLevel() == INFO &&
-                item.getMessage().toString().matches("User with address .+? requested: 1\\+3")));
-
-        assertTrue(log.stream().anyMatch(item -> item.getLevel() == INFO &&
-                item.getMessage().toString().matches(String.format("User %s with address .+? authenticated by Krb5Authenticator", kdcServer.clientPrincipalName2))));
-        assertTrue(log.stream().anyMatch(item -> item.getLevel() == INFO &&
-                item.getMessage().toString().matches("User with address .+? requested: 11\\+11")));
-        assertTrue(log.stream().anyMatch(item -> item.getLevel() == INFO &&
-                item.getMessage().toString().matches("User with address .+? requested: 11\\+12")));
-        assertTrue(log.stream().anyMatch(item -> item.getLevel() == INFO &&
-                item.getMessage().toString().matches("User with address .+? requested: 11\\+13")));
+        final String authenticatorName = Krb5Authenticator.class.getSimpleName();
+        assertTrue(logCaptor.getLogs().stream().anyMatch(m -> m.matches(
+                String.format("User %s with address .+? authenticated by %s", kdcServer.clientPrincipalName, authenticatorName))));
+        assertTrue(logCaptor.getLogs().stream().anyMatch(m ->
+                m.matches("User with address .+? requested: 1\\+1")));
+        assertTrue(logCaptor.getLogs().stream().anyMatch(m ->
+                m.matches("User with address .+? requested: 1\\+2")));
+        assertTrue(logCaptor.getLogs().stream().anyMatch(m ->
+                m.matches("User with address .+? requested: 1\\+3")));
+
+        assertTrue(logCaptor.getLogs().stream().anyMatch(m -> m.matches(
+                String.format("User %s with address .+? authenticated by %s", kdcServer.clientPrincipalName2, authenticatorName))));
+        assertTrue(logCaptor.getLogs().stream().anyMatch(m ->
+                m.matches("User with address .+? requested: 11\\+11")));
+        assertTrue(logCaptor.getLogs().stream().anyMatch(m ->
+                m.matches("User with address .+? requested: 11\\+12")));
+        assertTrue(logCaptor.getLogs().stream().anyMatch(m ->
+                m.matches("User with address .+? requested: 11\\+13")));
     }
 }
\ No newline at end of file
diff --git a/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinServerAuditLogIntegrateTest.java b/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinServerAuditLogIntegrateTest.java
index bc981ed..1bc22d4 100644
--- a/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinServerAuditLogIntegrateTest.java
+++ b/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinServerAuditLogIntegrateTest.java
@@ -18,13 +18,12 @@
  */
 package org.apache.tinkerpop.gremlin.server;
 
+import nl.altindag.log.LogCaptor;
 import org.apache.http.client.methods.CloseableHttpResponse;
 import org.apache.http.client.methods.HttpGet;
 import org.apache.http.impl.client.CloseableHttpClient;
 import org.apache.http.impl.client.HttpClients;
 import org.apache.http.util.EntityUtils;
-import org.apache.log4j.Logger;
-import org.apache.log4j.spi.LoggingEvent;
 import org.apache.tinkerpop.gremlin.driver.Client;
 import org.apache.tinkerpop.gremlin.driver.Cluster;
 import org.apache.tinkerpop.gremlin.driver.remote.DriverRemoteConnection;
@@ -37,19 +36,18 @@ import org.apache.tinkerpop.gremlin.server.auth.SimpleAuthenticator;
 import org.apache.tinkerpop.gremlin.server.channel.HttpChannelizer;
 import org.apache.tinkerpop.gremlin.server.handler.SaslAndHttpBasicAuthenticationHandler;
 import org.apache.tinkerpop.gremlin.structure.io.graphson.GraphSONTokens;
-import org.apache.tinkerpop.gremlin.util.Log4jRecordingAppender;
 import org.apache.tinkerpop.shaded.jackson.databind.JsonNode;
 import org.apache.tinkerpop.shaded.jackson.databind.ObjectMapper;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
 import org.junit.Test;
 import org.slf4j.LoggerFactory;
 
 import java.util.Base64;
 import java.util.HashMap;
-import java.util.List;
 import java.util.Map;
-import java.util.stream.Stream;
 
-import static org.apache.log4j.Level.INFO;
 import static org.apache.tinkerpop.gremlin.server.GremlinServer.AUDIT_LOGGER_NAME;
 import static org.apache.tinkerpop.gremlin.server.GremlinServerAuthKrb5IntegrateTest.TESTCONSOLE;
 import static org.junit.Assert.assertEquals;
@@ -64,7 +62,8 @@ import static org.junit.Assert.assertTrue;
  */
 public class GremlinServerAuditLogIntegrateTest extends AbstractGremlinServerIntegrationTest {
     private static final org.slf4j.Logger logger = LoggerFactory.getLogger(GremlinServerAuditLogIntegrateTest.class);
-    private Log4jRecordingAppender recordingAppender = null;
+
+    private static LogCaptor logCaptor;
 
     private final ObjectMapper mapper = new ObjectMapper();
     private final Base64.Encoder encoder = Base64.getUrlEncoder();
@@ -75,12 +74,23 @@ public class GremlinServerAuditLogIntegrateTest extends AbstractGremlinServerInt
 
     private KdcFixture kdcServer;
 
+    @BeforeClass
+    public static void setupLogCaptor() {
+        logCaptor = LogCaptor.forName(AUDIT_LOGGER_NAME);
+    }
+
+    @AfterClass
+    public static void tearDownAfterClass() {
+        logCaptor.close();
+    }
+
+    @Before
+    public void setupForEachTest() {
+        logCaptor.clearLogs();
+    }
+
     @Override
     public void setUp() throws Exception {
-        recordingAppender = new Log4jRecordingAppender();
-        final Logger rootLogger = Logger.getRootLogger();
-        rootLogger.addAppender(recordingAppender);
-
         try {
             final String moduleBaseDir = System.getProperty("basedir", ".");
             final String authConfigName = moduleBaseDir + "/src/test/resources/org/apache/tinkerpop/gremlin/server/gremlin-console-jaas.conf";
@@ -95,8 +105,6 @@ public class GremlinServerAuditLogIntegrateTest extends AbstractGremlinServerInt
 
     @Override
     public void tearDown() throws Exception {
-        final Logger rootLogger = Logger.getRootLogger();
-        rootLogger.removeAppender(recordingAppender);
         kdcServer.close();
         System.clearProperty("java.security.auth.login.config");
         super.tearDown();
@@ -166,12 +174,12 @@ public class GremlinServerAuditLogIntegrateTest extends AbstractGremlinServerInt
 
         // WebSocketChannelizer does not add SaslAuthenticationHandler for AllowAllAuthenticator,
         // so no authenticated user log line available
-        assertTrue(recordingAppender.logMatchesAny(AUDIT_LOGGER_NAME, INFO, String.format(
-                "User %s with address .+? requested: 1\\+1", AuthenticatedUser.ANONYMOUS_USERNAME)));
-        assertTrue(recordingAppender.logMatchesAny(AUDIT_LOGGER_NAME, INFO, String.format(
-                "User %s with address .+? requested: 1\\+2", AuthenticatedUser.ANONYMOUS_USERNAME)));
-        assertTrue(recordingAppender.logMatchesAny(AUDIT_LOGGER_NAME, INFO, String.format(
-                "User %s with address .+? requested: 1\\+3", AuthenticatedUser.ANONYMOUS_USERNAME)));
+        assertTrue(logCaptor.getLogs().stream().anyMatch(m -> m.matches(String.format(
+                "User %s with address .+? requested: 1\\+1", AuthenticatedUser.ANONYMOUS_USERNAME))));
+        assertTrue(logCaptor.getLogs().stream().anyMatch(m -> m.matches(String.format(
+                "User %s with address .+? requested: 1\\+2", AuthenticatedUser.ANONYMOUS_USERNAME))));
+        assertTrue(logCaptor.getLogs().stream().anyMatch(m -> m.matches(String.format(
+                "User %s with address .+? requested: 1\\+3", AuthenticatedUser.ANONYMOUS_USERNAME))));
     }
 
     @Test
@@ -196,20 +204,14 @@ public class GremlinServerAuditLogIntegrateTest extends AbstractGremlinServerInt
         Thread.sleep(1000);
 
         final String simpleAuthenticatorName = SimpleAuthenticator.class.getSimpleName();
-
-        final List<LoggingEvent> log = recordingAppender.getEvents();
-        final Stream<LoggingEvent> auditEvents = log.stream().filter(event -> event.getLoggerName().equals(AUDIT_LOGGER_NAME));
-        final LoggingEvent authEvent = auditEvents
-                .filter(event -> event.getMessage().toString().contains(simpleAuthenticatorName)).iterator().next();
-        final String authMsg = authEvent.getMessage().toString();
-        assertTrue(authEvent.getLevel() == INFO &&
-                authMsg.matches(String.format("User %s with address .+? authenticated by %s", username, simpleAuthenticatorName)));
-        assertTrue(log.stream().anyMatch(item -> item.getLevel() == INFO &&
-                item.getMessage().toString().matches("User stephen with address .+? requested: 1\\+1")));
-        assertTrue(log.stream().anyMatch(item -> item.getLevel() == INFO &&
-                item.getMessage().toString().matches("User stephen with address .+? requested: 1\\+2")));
-        assertTrue(log.stream().anyMatch(item -> item.getLevel() == INFO &&
-                item.getMessage().toString().matches("User stephen with address .+? requested: 1\\+3")));
+        assertTrue(logCaptor.getLogs().stream().anyMatch(m -> m.matches(
+                String.format("User %s with address .+? authenticated by %s", username, simpleAuthenticatorName))));
+        assertTrue(logCaptor.getLogs().stream().anyMatch(m -> m.matches(
+                "User stephen with address .+? requested: 1\\+1")));
+        assertTrue(logCaptor.getLogs().stream().anyMatch(m -> m.matches(
+                "User stephen with address .+? requested: 1\\+2")));
+        assertTrue(logCaptor.getLogs().stream().anyMatch(m -> m.matches(
+                "User stephen with address .+? requested: 1\\+3")));
     }
 
     @Test
@@ -228,19 +230,15 @@ public class GremlinServerAuditLogIntegrateTest extends AbstractGremlinServerInt
         stopServer();
         Thread.sleep(1000);
 
-        final List<LoggingEvent> log = recordingAppender.getEvents();
-        final Stream<LoggingEvent> auditEvents = log.stream().filter(event -> event.getLoggerName().equals(AUDIT_LOGGER_NAME));
-        final LoggingEvent authEvent = auditEvents
-                .filter(event -> event.getMessage().toString().contains("Krb5Authenticator")).iterator().next();
-        final String authMsg = authEvent.getMessage().toString();
-        assertTrue(authEvent.getLevel() == INFO &&
-                authMsg.matches(String.format("User %s with address .+? authenticated by Krb5Authenticator", kdcServer.clientPrincipalName)));
-        assertTrue(log.stream().anyMatch(item -> item.getLevel() == INFO &&
-                item.getMessage().toString().matches("User drankye with address .+? requested: 1\\+1")));
-        assertTrue(log.stream().anyMatch(item -> item.getLevel() == INFO &&
-                item.getMessage().toString().matches("User drankye with address .+? requested: 1\\+2")));
-        assertTrue(log.stream().anyMatch(item -> item.getLevel() == INFO &&
-                item.getMessage().toString().matches("User drankye with address .+? requested: 1\\+3")));
+        final String authenticatorName = Krb5Authenticator.class.getSimpleName();
+        assertTrue(logCaptor.getLogs().stream().anyMatch(m -> m.matches(
+                String.format("User %s with address .+? authenticated by %s", kdcServer.clientPrincipalName, authenticatorName))));
+        assertTrue(logCaptor.getLogs().stream().anyMatch(m -> m.matches(
+                "User drankye with address .+? requested: 1\\+1")));
+        assertTrue(logCaptor.getLogs().stream().anyMatch(m -> m.matches(
+                "User drankye with address .+? requested: 1\\+2")));
+        assertTrue(logCaptor.getLogs().stream().anyMatch(m -> m.matches(
+                "User drankye with address .+? requested: 1\\+3")));
     }
 
     @Test
@@ -259,15 +257,15 @@ public class GremlinServerAuditLogIntegrateTest extends AbstractGremlinServerInt
         stopServer();
         Thread.sleep(1000);
 
-        final List<LoggingEvent> log = recordingAppender.getEvents();
-        assertFalse(log.stream().anyMatch(item -> item.getLevel() == INFO &&
-                item.getMessage().toString().matches("User drankye with address .+? authenticated by Krb5Authenticator")));
-        assertFalse(log.stream().anyMatch(item -> item.getLevel() == INFO &&
-                item.getMessage().toString().matches("User drankye with address .+? requested: 1\\+1")));
-        assertFalse(log.stream().anyMatch(item -> item.getLevel() == INFO &&
-                item.getMessage().toString().matches("User drankye with address .+? requested: 1\\+2")));
-        assertFalse(log.stream().anyMatch(item -> item.getLevel() == INFO &&
-            item.getMessage().toString().matches("User drankye with address .+? requested: 1\\+3")));
+        final String authenticatorName = Krb5Authenticator.class.getSimpleName();
+        assertFalse(logCaptor.getLogs().stream().anyMatch(m -> m.matches(
+                String.format("User %s with address .+? authenticated by %s", kdcServer.clientPrincipalName, authenticatorName))));
+        assertFalse(logCaptor.getLogs().stream().anyMatch(m -> m.matches(
+                "User drankye with address .+? requested: 1\\+1")));
+        assertFalse(logCaptor.getLogs().stream().anyMatch(m -> m.matches(
+                "User drankye with address .+? requested: 1\\+2")));
+        assertFalse(logCaptor.getLogs().stream().anyMatch(m -> m.matches(
+                "User drankye with address .+? requested: 1\\+3")));
     }
 
     @Test
@@ -288,17 +286,11 @@ public class GremlinServerAuditLogIntegrateTest extends AbstractGremlinServerInt
         stopServer();
         Thread.sleep(1000);
 
-        final String simpleAuthenticatorName = SimpleAuthenticator.class.getSimpleName();
-
-        final List<LoggingEvent> log = recordingAppender.getEvents();
-        final Stream<LoggingEvent> auditEvents = log.stream().filter(event -> event.getLoggerName().equals(AUDIT_LOGGER_NAME));
-        final LoggingEvent authEvent = auditEvents
-                .filter(event -> event.getMessage().toString().contains(simpleAuthenticatorName)).iterator().next();
-        final String authMsg = authEvent.getMessage().toString();
-        assertTrue(authEvent.getLevel() == INFO &&
-                authMsg.matches(String.format("User stephen with address .+? authenticated by %s", simpleAuthenticatorName)));
-        assertTrue(log.stream().anyMatch(item -> item.getLevel() == INFO &&
-                item.getMessage().toString().matches("User stephen with address .+? requested: 2-1")));
+        final String authenticatorName = SimpleAuthenticator.class.getSimpleName();
+        assertTrue(logCaptor.getLogs().stream().anyMatch(m -> m.matches(
+                String.format("User stephen with address .+? authenticated by %s", authenticatorName))));
+        assertTrue(logCaptor.getLogs().stream().anyMatch(m -> m.matches(
+                "User stephen with address .+? requested: 2-1")));
     }
 
     @Test
@@ -320,17 +312,11 @@ public class GremlinServerAuditLogIntegrateTest extends AbstractGremlinServerInt
         stopServer();
         Thread.sleep(1000);
 
-        final String simpleAuthenticatorName = SimpleAuthenticator.class.getSimpleName();
-
-        final List<LoggingEvent> log = recordingAppender.getEvents();
-        final Stream<LoggingEvent> auditEvents = log.stream().filter(event -> event.getLoggerName().equals(AUDIT_LOGGER_NAME));
-        final LoggingEvent authEvent = auditEvents
-                .filter(event -> event.getMessage().toString().contains(simpleAuthenticatorName)).iterator().next();
-        final String authMsg = authEvent.getMessage().toString();
-        assertTrue(authEvent.getLevel() == INFO &&
-                authMsg.matches(String.format("User %s with address .+? authenticated by %s", username, simpleAuthenticatorName)));
-        assertTrue(log.stream().anyMatch(item -> item.getLevel() == INFO &&
-                item.getMessage().toString().matches("User .+? with address .+? requested: \\[\\[], \\[V\\(\\), count\\(\\)]]")));
+        final String authenticatorName = SimpleAuthenticator.class.getSimpleName();
+        assertTrue(logCaptor.getLogs().stream().anyMatch(m -> m.matches(
+                String.format("User %s with address .+? authenticated by %s", username, authenticatorName))));
+        assertTrue(logCaptor.getLogs().stream().anyMatch(m ->
+                m.matches("User .+? with address .+? requested: \\[\\[], \\[V\\(\\), count\\(\\)]]")));
     }
 
     @Test
@@ -362,27 +348,23 @@ public class GremlinServerAuditLogIntegrateTest extends AbstractGremlinServerInt
         stopServer();
         Thread.sleep(1000);
 
-        final List<LoggingEvent> log = recordingAppender.getEvents();
-        final Stream<LoggingEvent> auditEvents = log.stream().filter(event -> event.getLoggerName().equals(AUDIT_LOGGER_NAME));
-        final LoggingEvent authEvent = auditEvents
-                .filter(event -> event.getMessage().toString().contains("Krb5Authenticator")).iterator().next();
-        final String authMsg = authEvent.getMessage().toString();
-        assertTrue(authEvent.getLevel() == INFO &&
-                authMsg.matches(String.format("User %s with address .+? authenticated by Krb5Authenticator", kdcServer.clientPrincipalName)));
-        assertTrue(log.stream().anyMatch(item -> item.getLevel() == INFO &&
-                item.getMessage().toString().matches("User drankye with address .+? requested: 1\\+1")));
-        assertTrue(log.stream().anyMatch(item -> item.getLevel() == INFO &&
-                item.getMessage().toString().matches("User drankye with address .+? requested: 1\\+2")));
-        assertTrue(log.stream().anyMatch(item -> item.getLevel() == INFO &&
-                item.getMessage().toString().matches("User drankye with address .+? requested: 1\\+3")));
-
-        assertTrue(log.stream().anyMatch(item -> item.getLevel() == INFO &&
-                item.getMessage().toString().matches(String.format("User %s with address .+? authenticated by Krb5Authenticator", kdcServer.clientPrincipalName2))));
-        assertTrue(log.stream().anyMatch(item -> item.getLevel() == INFO &&
-                item.getMessage().toString().matches("User drankye2 with address .+? requested: 11\\+11")));
-        assertTrue(log.stream().anyMatch(item -> item.getLevel() == INFO &&
-                item.getMessage().toString().matches("User drankye2 with address .+? requested: 11\\+12")));
-        assertTrue(log.stream().anyMatch(item -> item.getLevel() == INFO &&
-                item.getMessage().toString().matches("User drankye2 with address .+? requested: 11\\+13")));
+        final String authenticatorName = Krb5Authenticator.class.getSimpleName();
+        assertTrue(logCaptor.getLogs().stream().anyMatch(m -> m.matches(
+                String.format("User %s with address .+? authenticated by %s", kdcServer.clientPrincipalName, authenticatorName))));
+        assertTrue(logCaptor.getLogs().stream().anyMatch(m ->
+                m.matches("User drankye with address .+? requested: 1\\+1")));
+        assertTrue(logCaptor.getLogs().stream().anyMatch(m ->
+                m.matches("User drankye with address .+? requested: 1\\+2")));
+        assertTrue(logCaptor.getLogs().stream().anyMatch(m ->
+                m.matches("User drankye with address .+? requested: 1\\+3")));
+
+        assertTrue(logCaptor.getLogs().stream().anyMatch(m -> m.matches(
+                String.format("User %s with address .+? authenticated by %s", kdcServer.clientPrincipalName2, authenticatorName))));
+        assertTrue(logCaptor.getLogs().stream().anyMatch(m ->
+                m.matches("User drankye2 with address .+? requested: 11\\+11")));
+        assertTrue(logCaptor.getLogs().stream().anyMatch(m ->
+                m.matches("User drankye2 with address .+? requested: 11\\+12")));
+        assertTrue(logCaptor.getLogs().stream().anyMatch(m ->
+                m.matches("User drankye2 with address .+? requested: 11\\+13")));
     }
 }
\ No newline at end of file
diff --git a/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinServerAuthKrb5IntegrateTest.java b/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinServerAuthKrb5IntegrateTest.java
index 2244fb6..6307a03 100644
--- a/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinServerAuthKrb5IntegrateTest.java
+++ b/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinServerAuthKrb5IntegrateTest.java
@@ -19,7 +19,6 @@
 package org.apache.tinkerpop.gremlin.server;
 
 import org.apache.commons.lang3.exception.ExceptionUtils;
-import org.apache.log4j.Level;
 import org.apache.tinkerpop.gremlin.driver.Client;
 import org.apache.tinkerpop.gremlin.driver.Cluster;
 import org.apache.tinkerpop.gremlin.driver.MessageSerializer;
@@ -53,16 +52,9 @@ public class GremlinServerAuthKrb5IntegrateTest extends AbstractGremlinServerInt
     static final String TESTCONSOLE_NOT_LOGGED_IN = "UserNotLoggedIn";
 
     private KdcFixture kdcServer;
-    private Level previousLogLevel;
 
     @Override
     public void setUp() throws Exception {
-        // this logger is noisy for travis and we don't assert anything and the error is already tracked on
-        // the server so we can trim the logs a bit with this.
-        final org.apache.log4j.Logger handlerLogger = org.apache.log4j.Logger.getLogger(
-                "org.apache.tinkerpop.gremlin.driver.Handler$GremlinResponseHandler");
-        previousLogLevel = handlerLogger.getLevel();
-        handlerLogger.setLevel(Level.OFF);
 
         try {
             final String projectBaseDir = System.getProperty("basedir", ".");
@@ -78,10 +70,6 @@ public class GremlinServerAuthKrb5IntegrateTest extends AbstractGremlinServerInt
 
     @Override
     public void tearDown() throws Exception {
-        final org.apache.log4j.Logger handlerLogger = org.apache.log4j.Logger.getLogger(
-                "org.apache.tinkerpop.gremlin.driver.Handler$GremlinResponseHandler");
-        handlerLogger.setLevel(previousLogLevel);
-
         kdcServer.close();
         System.clearProperty("java.security.auth.login.config");
         super.tearDown();
diff --git a/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinServerAuthzIntegrateTest.java b/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinServerAuthzIntegrateTest.java
index 00eacda..b3069fd 100644
--- a/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinServerAuthzIntegrateTest.java
+++ b/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinServerAuthzIntegrateTest.java
@@ -18,12 +18,12 @@
  */
 package org.apache.tinkerpop.gremlin.server;
 
+import nl.altindag.log.LogCaptor;
 import org.apache.http.client.methods.CloseableHttpResponse;
 import org.apache.http.client.methods.HttpGet;
 import org.apache.http.impl.client.CloseableHttpClient;
 import org.apache.http.impl.client.HttpClients;
 import org.apache.http.util.EntityUtils;
-import org.apache.log4j.Logger;
 import org.apache.tinkerpop.gremlin.driver.Client;
 import org.apache.tinkerpop.gremlin.driver.Cluster;
 import org.apache.tinkerpop.gremlin.driver.exception.ResponseException;
@@ -31,26 +31,28 @@ import org.apache.tinkerpop.gremlin.driver.message.ResponseStatusCode;
 import org.apache.tinkerpop.gremlin.driver.remote.DriverRemoteConnection;
 import org.apache.tinkerpop.gremlin.process.traversal.AnonymousTraversalSource;
 import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource;
+import org.apache.tinkerpop.gremlin.process.traversal.strategy.verification.AbstractWarningVerificationStrategy;
 import org.apache.tinkerpop.gremlin.server.auth.AllowAllAuthenticator;
 import org.apache.tinkerpop.gremlin.server.auth.SimpleAuthenticator;
 import org.apache.tinkerpop.gremlin.server.authz.AllowListAuthorizer;
 import org.apache.tinkerpop.gremlin.server.channel.HttpChannelizer;
 import org.apache.tinkerpop.gremlin.server.handler.SaslAndHttpBasicAuthenticationHandler;
 import org.apache.tinkerpop.gremlin.structure.io.graphson.GraphSONTokens;
-import org.apache.tinkerpop.gremlin.util.Log4jRecordingAppender;
 import org.apache.tinkerpop.gremlin.util.function.Lambda;
 import org.apache.tinkerpop.shaded.jackson.databind.JsonNode;
 import org.apache.tinkerpop.shaded.jackson.databind.ObjectMapper;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
 import org.junit.Test;
 
 import java.util.Base64;
 import java.util.HashMap;
 import java.util.Objects;
 
-import static org.apache.log4j.Level.INFO;
-import static org.apache.tinkerpop.gremlin.server.GremlinServer.AUDIT_LOGGER_NAME;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.core.Is.is;
 import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 
 /**
@@ -60,25 +62,24 @@ import static org.junit.Assert.fail;
  * @author Marc de Lignie
  */
 public class GremlinServerAuthzIntegrateTest extends AbstractGremlinServerIntegrationTest {
+    private static LogCaptor logCaptor;
 
-    private Log4jRecordingAppender recordingAppender;
     private final ObjectMapper mapper = new ObjectMapper();
     private final Base64.Encoder encoder = Base64.getUrlEncoder();
 
-    @Override
-    public void setUp() throws Exception {
-        recordingAppender = new Log4jRecordingAppender();
-        final Logger rootLogger = Logger.getRootLogger();
-        rootLogger.addAppender(recordingAppender);
-        super.setUp();
+    @BeforeClass
+    public static void setupLogCaptor() {
+        logCaptor = LogCaptor.forRoot();
     }
 
-    @Override
-    public void tearDown() throws Exception {
-        super.tearDown();
-        final Logger rootLogger = Logger.getRootLogger();
-        rootLogger.removeAppender(recordingAppender);
-        super.tearDown();
+    @Before
+    public void resetLogs() {
+        logCaptor.clearLogs();
+    }
+
+    @AfterClass
+    public static void tearDownClass() {
+        logCaptor.close();
     }
 
     /**
@@ -176,9 +177,9 @@ public class GremlinServerAuthzIntegrateTest extends AbstractGremlinServerIntegr
             stopServer();
             Thread.sleep(1000);
 
-            assertTrue(recordingAppender.logMatchesAny(AUDIT_LOGGER_NAME, INFO,
+            assertThat(logCaptor.getLogs().stream().anyMatch(m -> m.matches(
                     "User stephen with address .+? attempted an unauthorized request for bytecode operation: " +
-                            "\\[\\[], \\[V\\(\\), map\\(lambda\\[it.get\\(\\).value\\('name'\\)]\\), count\\(\\)]]"));
+                    "\\[\\[], \\[V\\(\\), map\\(lambda\\[it.get\\(\\).value\\('name'\\)]\\), count\\(\\)]]")), is(true));
         } finally {
             cluster.close();
         }
@@ -237,8 +238,8 @@ public class GremlinServerAuthzIntegrateTest extends AbstractGremlinServerIntegr
             stopServer();
             Thread.sleep(1000);
 
-            assertTrue(recordingAppender.logMatchesAny(AUDIT_LOGGER_NAME, INFO,
-                    "User stephen with address .+? attempted an unauthorized request for eval operation: 1\\+1"));
+            assertThat(logCaptor.getLogs().stream().anyMatch(m -> m.matches(
+                    "User stephen with address .+? attempted an unauthorized request for eval operation: 1\\+1")), is(true));
         } finally {
             cluster.close();
         }
@@ -337,8 +338,8 @@ public class GremlinServerAuthzIntegrateTest extends AbstractGremlinServerIntegr
         stopServer();
         Thread.sleep(1000);
 
-        assertTrue(recordingAppender.logMatchesAny(AUDIT_LOGGER_NAME, INFO,
-                "User stephen with address .+? attempted an unauthorized http request: 3-1"));
+        assertThat(logCaptor.getLogs().stream().anyMatch(m -> m.matches(
+                "User stephen with address .+? attempted an unauthorized http request: 3-1")), is(true));
     }
 
     @Test
diff --git a/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinServerIntegrateTest.java b/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinServerIntegrateTest.java
index 7d9983f..0e6f552 100644
--- a/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinServerIntegrateTest.java
+++ b/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinServerIntegrateTest.java
@@ -18,11 +18,12 @@
  */
 package org.apache.tinkerpop.gremlin.server;
 
+import ch.qos.logback.classic.Level;
+import ch.qos.logback.classic.Logger;
+import nl.altindag.log.LogCaptor;
 import org.apache.commons.configuration2.BaseConfiguration;
 import org.apache.commons.configuration2.Configuration;
 import org.apache.commons.lang3.exception.ExceptionUtils;
-import org.apache.log4j.Level;
-import org.apache.log4j.Logger;
 import org.apache.tinkerpop.gremlin.TestHelper;
 import org.apache.tinkerpop.gremlin.driver.Client;
 import org.apache.tinkerpop.gremlin.driver.Cluster;
@@ -40,29 +41,29 @@ import org.apache.tinkerpop.gremlin.groovy.jsr223.GremlinGroovyScriptEngine;
 import org.apache.tinkerpop.gremlin.groovy.jsr223.GroovyCompilerGremlinPlugin;
 import org.apache.tinkerpop.gremlin.groovy.jsr223.customizer.SimpleSandboxExtension;
 import org.apache.tinkerpop.gremlin.jsr223.ScriptFileGremlinPlugin;
+import org.apache.tinkerpop.gremlin.server.handler.OpSelectorHandler;
 import org.apache.tinkerpop.gremlin.server.handler.UnifiedHandler;
 import org.apache.tinkerpop.gremlin.structure.RemoteGraph;
 import org.apache.tinkerpop.gremlin.process.traversal.Traversal;
 import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource;
 import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__;
-import org.apache.tinkerpop.gremlin.server.handler.OpSelectorHandler;
 import org.apache.tinkerpop.gremlin.server.op.AbstractEvalOpProcessor;
 import org.apache.tinkerpop.gremlin.server.op.standard.StandardOpProcessor;
 import org.apache.tinkerpop.gremlin.structure.Graph;
 import org.apache.tinkerpop.gremlin.structure.T;
 import org.apache.tinkerpop.gremlin.structure.Vertex;
-import org.apache.tinkerpop.gremlin.util.Log4jRecordingAppender;
 import org.apache.tinkerpop.gremlin.util.function.Lambda;
 import org.hamcrest.CoreMatchers;
 import org.hamcrest.Matchers;
 import org.junit.After;
+import org.junit.AfterClass;
 import org.junit.Before;
+import org.junit.BeforeClass;
 import org.junit.Test;
 
 import org.slf4j.LoggerFactory;
 
 import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.HashMap;
 import java.util.Iterator;
 import java.util.List;
@@ -104,7 +105,6 @@ public class GremlinServerIntegrateTest extends AbstractGremlinServerIntegration
     private Level previousLogLevel;
     private static final org.slf4j.Logger logger = LoggerFactory.getLogger(GremlinServerIntegrateTest.class);
 
-    private Log4jRecordingAppender recordingAppender = null;
     private final Supplier<Graph> graphGetter = () -> server.getServerGremlinExecutor().getGraphManager().getGraph("graph");
     private final Configuration conf = new BaseConfiguration() {{
         setProperty(Graph.GRAPH, RemoteGraph.class.getName());
@@ -115,36 +115,42 @@ public class GremlinServerIntegrateTest extends AbstractGremlinServerIntegration
         setProperty("clusterConfiguration.hosts", "localhost");
     }};
 
+    private static LogCaptor logCaptor;
+
+    @BeforeClass
+    public static void setupLogCaptor() {
+        logCaptor = LogCaptor.forRoot();
+    }
+
+    @AfterClass
+    public static void tearDownAfterClass() {
+        logCaptor.close();
+    }
+
     @Before
     public void setupForEachTest() {
-        recordingAppender = new Log4jRecordingAppender();
-        final Logger rootLogger = Logger.getRootLogger();
 
         if (name.getMethodName().equals("shouldPingChannelIfClientDies") ||
                 name.getMethodName().equals("shouldCloseChannelIfClientDoesntRespond")) {
-            final org.apache.log4j.Logger opSelectorHandlerLogger = org.apache.log4j.Logger.getLogger(OpSelectorHandler.class);
-            final org.apache.log4j.Logger unifiedHandlerLogger = org.apache.log4j.Logger.getLogger(UnifiedHandler.class);
+            final Logger opSelectorHandlerLogger = (Logger) LoggerFactory.getLogger(OpSelectorHandler.class);
+            final Logger unifiedHandlerLogger = (Logger) LoggerFactory.getLogger(UnifiedHandler.class);
             previousLogLevel = opSelectorHandlerLogger.getLevel();
             opSelectorHandlerLogger.setLevel(Level.INFO);
             unifiedHandlerLogger.setLevel(Level.INFO);
         }
 
-        rootLogger.addAppender(recordingAppender);
+        logCaptor.clearLogs();
     }
 
     @After
     public void teardownForEachTest() {
-        final Logger rootLogger = Logger.getRootLogger();
-
         if (name.getMethodName().equals("shouldPingChannelIfClientDies")||
                 name.getMethodName().equals("shouldCloseChannelIfClientDoesntRespond")) {
-            final org.apache.log4j.Logger opSelectorHandlerLogger = org.apache.log4j.Logger.getLogger(OpSelectorHandler.class);
+            final Logger opSelectorHandlerLogger = (Logger) LoggerFactory.getLogger(OpSelectorHandler.class);
             opSelectorHandlerLogger.setLevel(previousLogLevel);
-            final org.apache.log4j.Logger unifiedHandlerLogger = org.apache.log4j.Logger.getLogger(UnifiedHandler.class);
+            final Logger unifiedHandlerLogger = (Logger) LoggerFactory.getLogger(UnifiedHandler.class);
             unifiedHandlerLogger.setLevel(previousLogLevel);
         }
-
-        rootLogger.removeAppender(recordingAppender);
     }
 
     /**
@@ -330,7 +336,8 @@ public class GremlinServerIntegrateTest extends AbstractGremlinServerIntegration
         // will autoclose the channel
         Thread.sleep(2000);
 
-        assertThat(recordingAppender.logContainsAny(".*Closing channel - client is disconnected after idle period of .*$"), is(true));
+        assertThat(logCaptor.getLogs().stream().anyMatch(m -> m.matches(
+                ".*Closing channel - client is disconnected after idle period of .*$")), is(true));
 
         client.close();
     }
@@ -350,7 +357,8 @@ public class GremlinServerIntegrateTest extends AbstractGremlinServerIntegration
         // stop the server to be sure that logs flush
         stopServer();
 
-        assertThat(recordingAppender.logContainsAny(".*Checking channel - sending ping to client after idle period of .*$"), is(true));
+        assertThat(logCaptor.getLogs().stream().anyMatch(m -> m.matches(
+                ".*Checking channel - sending ping to client after idle period of .*$")), is(true));
     }
 
     @Test
@@ -561,7 +569,8 @@ public class GremlinServerIntegrateTest extends AbstractGremlinServerIntegration
             assertThat(faulty.get(), is(false));
             assertThat(expected.get(), is(true));
 
-            assertThat(recordingAppender.getMessages().stream().anyMatch(m -> m.contains("Pausing response writing as writeBufferHighWaterMark exceeded on")), is(true));
+            assertThat(logCaptor.getLogs().stream().anyMatch(m -> m.contains(
+                    "Pausing response writing as writeBufferHighWaterMark exceeded on")), is(true));
         } catch (Exception ex) {
             fail("Shouldn't have tossed an exception");
         } finally {
diff --git a/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinServerSessionIntegrateTest.java b/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinServerSessionIntegrateTest.java
index 588d36b..af7f788 100644
--- a/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinServerSessionIntegrateTest.java
+++ b/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinServerSessionIntegrateTest.java
@@ -18,12 +18,12 @@
  */
 package org.apache.tinkerpop.gremlin.server;
 
+import ch.qos.logback.classic.Level;
+import ch.qos.logback.classic.Logger;
+import nl.altindag.log.LogCaptor;
 import org.apache.commons.lang3.exception.ExceptionUtils;
-import org.apache.log4j.Level;
-import org.apache.log4j.Logger;
 import org.apache.tinkerpop.gremlin.driver.Client;
 import org.apache.tinkerpop.gremlin.driver.Cluster;
-import org.apache.tinkerpop.gremlin.driver.RequestOptions;
 import org.apache.tinkerpop.gremlin.driver.Result;
 import org.apache.tinkerpop.gremlin.driver.ResultSet;
 import org.apache.tinkerpop.gremlin.driver.Tokens;
@@ -35,10 +35,12 @@ import org.apache.tinkerpop.gremlin.driver.simple.SimpleClient;
 import org.apache.tinkerpop.gremlin.server.channel.UnifiedChannelizer;
 import org.apache.tinkerpop.gremlin.server.op.session.Session;
 import org.apache.tinkerpop.gremlin.server.op.session.SessionOpProcessor;
-import org.apache.tinkerpop.gremlin.util.Log4jRecordingAppender;
 import org.junit.After;
+import org.junit.AfterClass;
 import org.junit.Before;
+import org.junit.BeforeClass;
 import org.junit.Test;
+import org.slf4j.LoggerFactory;
 
 import java.io.File;
 import java.util.ArrayList;
@@ -63,31 +65,39 @@ import static org.junit.Assume.assumeThat;
  * @author Stephen Mallette (http://stephen.genoprime.com)
  */
 public class GremlinServerSessionIntegrateTest extends AbstractGremlinServerIntegrationTest {
-    private Log4jRecordingAppender recordingAppender = null;
+    private static LogCaptor logCaptor;
     private Level originalLevel;
 
+    @BeforeClass
+    public static void setupLogCaptor() {
+        logCaptor = LogCaptor.forRoot();
+    }
+
+    @AfterClass
+    public static void tearDownAfterClass() {
+        logCaptor.close();
+    }
+
     @Before
     public void setupForEachTest() {
-        recordingAppender = new Log4jRecordingAppender();
-        final Logger rootLogger = Logger.getRootLogger();
-        originalLevel = rootLogger.getLevel();
         final String nameOfTest = name.getMethodName();
         switch (nameOfTest) {
             case "shouldCloseSessionOnceOnRequest":
             case "shouldHaveTheSessionTimeout":
             case "shouldCloseSessionOnClientClose":
-                final org.apache.log4j.Logger sessionLogger = org.apache.log4j.Logger.getLogger(Session.class);
+                final Logger sessionLogger = (Logger) LoggerFactory.getLogger(Session.class);
+                originalLevel = sessionLogger.getLevel();
                 sessionLogger.setLevel(Level.DEBUG);
                 break;
         }
-        rootLogger.addAppender(recordingAppender);
+
+        logCaptor.clearLogs();
     }
 
     @After
     public void teardownForEachTest() {
-        final org.apache.log4j.Logger sessionLogger = org.apache.log4j.Logger.getLogger(Session.class);
+        final Logger sessionLogger = (Logger) LoggerFactory.getLogger(Session.class);
         sessionLogger.setLevel(originalLevel);
-        sessionLogger.removeAppender(recordingAppender);
     }
 
     /**
@@ -269,8 +279,8 @@ public class GremlinServerSessionIntegrateTest extends AbstractGremlinServerInte
         if (isUsingUnifiedChannelizer()) {
             assertThat(((UnifiedChannelizer) server.getChannelizer()).getUnifiedHandler().isActiveSession(name.getMethodName()), is(false));
         } else {
-            assertThat(recordingAppender.getMessages(), hasItem("DEBUG - Skipped attempt to close open graph transactions on shouldCloseSessionOnClientClose - close was forced\n"));
-            assertThat(recordingAppender.getMessages(), hasItem("DEBUG - Session shouldCloseSessionOnClientClose closed\n"));
+            assertThat(logCaptor.getLogs(), hasItem("Skipped attempt to close open graph transactions on shouldCloseSessionOnClientClose - close was forced"));
+            assertThat(logCaptor.getLogs(), hasItem("Session shouldCloseSessionOnClientClose closed"));
         }
 
         // try to reconnect to that session and make sure no state is there
@@ -476,8 +486,8 @@ public class GremlinServerSessionIntegrateTest extends AbstractGremlinServerInte
         if (isUsingUnifiedChannelizer()) {
             assertThat(((UnifiedChannelizer) server.getChannelizer()).getUnifiedHandler().isActiveSession(name.getMethodName()), is(false));
         } else {
-            assertEquals(1, recordingAppender.getMessages().stream()
-                    .filter(msg -> msg.equals("DEBUG - Session shouldCloseSessionOnceOnRequest closed\n")).count());
+            assertEquals(1, logCaptor.getLogs().stream()
+                    .filter(msg -> msg.equals("Session shouldCloseSessionOnceOnRequest closed")).count());
         }
     }
 
@@ -530,8 +540,8 @@ public class GremlinServerSessionIntegrateTest extends AbstractGremlinServerInte
             assertThat(((UnifiedChannelizer) server.getChannelizer()).getUnifiedHandler().isActiveSession(name.getMethodName()), is(false));
         } else {
             // there will be one for the timeout and a second for closing the cluster
-            assertEquals(2, recordingAppender.getMessages().stream()
-                    .filter(msg -> msg.equals("DEBUG - Session shouldHaveTheSessionTimeout closed\n")).count());
+            assertEquals(2, logCaptor.getLogs().stream()
+                    .filter(msg -> msg.equals("Session shouldHaveTheSessionTimeout closed")).count());
         }
     }
 
diff --git a/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/util/Log4jRecordingAppender.java b/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/util/Log4jRecordingAppender.java
deleted file mode 100644
index 9a59c06..0000000
--- a/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/util/Log4jRecordingAppender.java
+++ /dev/null
@@ -1,85 +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.tinkerpop.gremlin.util;
-
-import org.apache.log4j.AppenderSkeleton;
-import org.apache.log4j.Level;
-import org.apache.log4j.PatternLayout;
-import org.apache.log4j.spi.LoggingEvent;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.regex.Pattern;
-
-/**
- * Provides a way to gather logging events for purpose of testing log output.
- *
- * @author Stephen Mallette (http://stephen.genoprime.com)
- */
-public class Log4jRecordingAppender extends AppenderSkeleton {
-    private final List<String> messages = new ArrayList<>();
-    private final List<LoggingEvent> events = new ArrayList<>();
-
-    public Log4jRecordingAppender() {
-        super();
-        setLayout(new PatternLayout("%p - %m%n")); // note the EOLN char(s) appended
-    }
-
-    @Override
-    protected void append(final LoggingEvent event) {
-        messages.add(layout.format(event));
-        events.add(event);
-    }
-
-    @Override
-    public void close() {
-    }
-
-    @Override
-    public boolean requiresLayout() {
-        return true;
-    }
-
-    public List<String> getMessages() { return messages; }
-
-    public List<LoggingEvent> getEvents() { return events; }
-
-    public void clear() {
-        messages.clear();
-    }
-
-    /**
-     * @param regex not null
-     * @return true if there is a substring of a message matching the regular expression, where:
-     *         . matches also the EOLN char(s) defined in the layout.
-     *         $ matches the end of the string
-     */
-    public boolean logContainsAny(final String regex) {
-        Pattern pattern = Pattern.compile(regex, Pattern.DOTALL);
-        return messages.stream().anyMatch(m -> pattern.matcher( m ).find());
-    }
-
-    public boolean logContainsAny(final String loggerName, final Level level, final String fragment) {
-        return events.stream().anyMatch(m -> m.getLoggerName().equals(loggerName) &&
-                m.getLevel().equals(level) && m.getMessage().toString().contains(fragment));
-    }
-    public boolean logMatchesAny(final String loggerName, final Level level, final String regex) {
-        return events.stream().anyMatch(m -> m.getLoggerName().equals(loggerName) &&
-                m.getLevel().equals(level) && m.getMessage().toString().matches(regex));
-    }
-}
diff --git a/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/util/Log4jRecordingAppenderTest.java b/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/util/Log4jRecordingAppenderTest.java
deleted file mode 100644
index 05cb437..0000000
--- a/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/util/Log4jRecordingAppenderTest.java
+++ /dev/null
@@ -1,86 +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.tinkerpop.gremlin.util;
-
-import org.apache.log4j.Level;
-import org.apache.log4j.Logger;
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.slf4j.LoggerFactory;
-
-import static org.hamcrest.CoreMatchers.is;
-import static org.junit.Assert.assertEquals;
-import static org.hamcrest.MatcherAssert.assertThat;
-
-/**
- * @author Stephen Mallette (http://stephen.genoprime.com)
- */
-public class Log4jRecordingAppenderTest {
-    private static final org.slf4j.Logger logger = LoggerFactory.getLogger(Log4jRecordingAppenderTest.class);
-    private Log4jRecordingAppender recordingAppender = null;
-    private static final String lineSeparator = System.getProperty("line.separator");
-
-    private Level originalConfiguredLevel = null;
-
-    @Before
-    public void setupForEachTest() {
-        recordingAppender = new Log4jRecordingAppender();
-        final Logger rootLogger = Logger.getRootLogger();
-        if (null == originalConfiguredLevel) originalConfiguredLevel = rootLogger.getLevel();
-        rootLogger.addAppender(recordingAppender);
-        rootLogger.setLevel(Level.ALL);
-
-        logger.error("ERROR");
-        logger.warn("WARN");
-        logger.info("INFO");
-    }
-
-    @After
-    public void teardownForEachTest() {
-        final Logger rootLogger = Logger.getRootLogger();
-        rootLogger.removeAppender(recordingAppender);
-        rootLogger.setLevel(originalConfiguredLevel);
-    }
-
-    @Test
-    public void shouldRecordMessages() {
-        assertEquals(3, recordingAppender.getMessages().size());
-        assertEquals("ERROR - ERROR" + lineSeparator, recordingAppender.getMessages().get(0));
-        assertEquals("WARN - WARN"  + lineSeparator, recordingAppender.getMessages().get(1));
-        assertEquals("INFO - INFO" + lineSeparator, recordingAppender.getMessages().get(2));
-    }
-
-    @Test
-    public void shouldMatchAnyMessages() {
-        assertThat(recordingAppender.logContainsAny("ERROR.*"), is(true));
-    }
-
-    @Test
-    public void shouldMatchNoMessages() {
-        assertThat(recordingAppender.logContainsAny("this is not here"), is(false));
-    }
-
-    @Test
-    public void shouldClearMessages() {
-        assertEquals(3, recordingAppender.getMessages().size());
-        recordingAppender.clear();
-        assertEquals(0, recordingAppender.getMessages().size());
-    }
-}
diff --git a/gremlin-server/src/test/resources/log4j-silent.properties b/gremlin-server/src/test/resources/log4j-silent.properties
deleted file mode 100644
index 1825bb0..0000000
--- a/gremlin-server/src/test/resources/log4j-silent.properties
+++ /dev/null
@@ -1,23 +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.
-
-# this file should always have logging set to OFF.  it seems, however, that an appender of some sort is
-# required or else some logs throw error and use other log4j.properties files on the path.
-log4j.rootLogger=OFF, stdout
-log4j.appender.stdout=org.apache.log4j.ConsoleAppender
-log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
-log4j.appender.stdout.layout.ConversionPattern=[%p] %C - %m%n
\ No newline at end of file
diff --git a/gremlin-server/src/test/resources/log4j-test.properties b/gremlin-server/src/test/resources/log4j-test.properties
deleted file mode 100644
index 4485712..0000000
--- a/gremlin-server/src/test/resources/log4j-test.properties
+++ /dev/null
@@ -1,28 +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.
-
-log4j.rootLogger=WARN, stdout
-log4j.appender.stdout=org.apache.log4j.ConsoleAppender
-log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
-log4j.appender.stdout.layout.ConversionPattern=[%p] %C - %m%n
-
-log4j.logger.org.apache.tinkerpop.gremlin.server.AbstractChannelizer=ERROR
-log4j.logger.org.apache.tinkerpop.gremlin.server.AbstractGremlinServerIntegrationTest=INFO
-log4j.logger.org.apache.tinkerpop.gremlin.server.op.AbstractEvalOpProcessor=ERROR
-log4j.logger.org.apache.tinkerpop.gremlin.server.handler.MultiTaskSession=ERROR
-log4j.logger.org.apache.tinkerpop.gremlin.server.handler.SingleTaskSession=ERROR
-log4j.logger.audit.org.apache.tinkerpop.gremlin.server=INFO
diff --git a/gremlin-server/src/test/resources/logback-silent.xml b/gremlin-server/src/test/resources/logback-silent.xml
new file mode 100644
index 0000000..4e7e08b
--- /dev/null
+++ b/gremlin-server/src/test/resources/logback-silent.xml
@@ -0,0 +1,27 @@
+<!--
+Licensed to the Apache Software Foundation (ASF) under one or more
+contributor license agreements.  See the NOTICE file distributed with
+this work for additional information regarding copyright ownership.
+The ASF licenses this file to You under the Apache License, Version 2.0
+(the "License"); you may not use this file except in compliance with
+the License.  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+-->
+<configuration>
+    <appender name="stdout" class="ch.qos.logback.core.ConsoleAppender">
+        <encoder>
+            <pattern>[%p] %C - %m%n</pattern>
+        </encoder>
+    </appender>
+    <logger name="org.apache.tinkerpop.gremlin.server.Context" level="WARN"/>
+    <root level="OFF">
+        <appender-ref ref="stdout"/>
+    </root>
+</configuration>
\ No newline at end of file
diff --git a/gremlin-server/src/test/resources/logback-test.xml b/gremlin-server/src/test/resources/logback-test.xml
new file mode 100644
index 0000000..b115427
--- /dev/null
+++ b/gremlin-server/src/test/resources/logback-test.xml
@@ -0,0 +1,36 @@
+<!--
+Licensed to the Apache Software Foundation (ASF) under one or more
+contributor license agreements.  See the NOTICE file distributed with
+this work for additional information regarding copyright ownership.
+The ASF licenses this file to You under the Apache License, Version 2.0
+(the "License"); you may not use this file except in compliance with
+the License.  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+-->
+<configuration>
+    <appender name="stdout" class="ch.qos.logback.core.ConsoleAppender">
+        <encoder>
+            <pattern>[%p] %C - %m%n</pattern>
+        </encoder>
+    </appender>
+    <logger name="org.apache.tinkerpop.gremlin.server.handler.MultiTaskSession" level="ERROR"/>
+    <logger name="org.apache.tinkerpop.gremlin.server.op.AbstractEvalOpProcessor" level="ERROR"/>
+    <logger name="org.apache.tinkerpop.gremlin.server.op.traversal.TraversalOpProcessor" level="ERROR"/>
+    <logger name="org.apache.tinkerpop.gremlin.server.AbstractGremlinServerIntegrationTest" level="INFO"/>
+    <logger name="audit.org.apache.tinkerpop.gremlin.server" level="INFO"/>
+    <logger name="org.apache.tinkerpop.gremlin.server.handler.SingleTaskSession" level="ERROR"/>
+    <logger name="org.apache.tinkerpop.gremlin.server.AbstractChannelizer" level="ERROR"/>
+    <!-- this logger is noisy and we don't assert anything and the error is already tracked on the server so we can
+         trim the logs a bit with this. -->
+    <logger name="org.apache.tinkerpop.gremlin.driver.Handler$GremlinResponseHandler" level="OFF"/>
+    <root level="WARN">
+        <appender-ref ref="stdout"/>
+    </root>
+</configuration>
\ No newline at end of file
diff --git a/gremlin-test/pom.xml b/gremlin-test/pom.xml
index 8a58fb1..343159c 100644
--- a/gremlin-test/pom.xml
+++ b/gremlin-test/pom.xml
@@ -48,8 +48,8 @@ limitations under the License.
             <artifactId>hamcrest</artifactId>
         </dependency>
         <dependency>
-            <groupId>org.slf4j</groupId>
-            <artifactId>slf4j-log4j12</artifactId>
+            <groupId>ch.qos.logback</groupId>
+            <artifactId>logback-classic</artifactId>
             <optional>true</optional>
         </dependency>
         <dependency>
@@ -119,7 +119,9 @@ limitations under the License.
                         <groupId>org.apache.maven.plugins</groupId>
                         <artifactId>maven-surefire-plugin</artifactId>
                         <configuration>
-                            <argLine>-Dlog4j.configuration=${log4j-test.properties} -Dbuild.dir=${project.build.directory} -Dis.testing=true -Djava.net.preferIPv4Stack=true ${suresafeArgs}
+                            <argLine>-Dlogback.configurationFile=${logback-test.properties}
+                                -Dbuild.dir=${project.build.directory} -Dis.testing=true -Djava.net.preferIPv4Stack=true
+                                ${suresafeArgs}
                             </argLine>
                             <excludes>
                                 <exclude>TraversalInterruptionTest.java</exclude>
diff --git a/gremlin-test/src/test/resources/log4j-silent.properties b/gremlin-test/src/test/resources/log4j-silent.properties
deleted file mode 100644
index 98d9e2a..0000000
--- a/gremlin-test/src/test/resources/log4j-silent.properties
+++ /dev/null
@@ -1,29 +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.
-
-# this file should always have logging set to OFF.  it seems, however, that an appender of some sort is
-# required or else some logs throw error and use other log4j.properties files on the path.
-log4j.rootLogger=OFF, stdout
-log4j.appender.stdout=org.apache.log4j.ConsoleAppender
-log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
-log4j.appender.stdout.layout.ConversionPattern=[%p] %C - %m%n
-
-# need to turn this on as this test actually tests "logging" - needs INFO at minimum for tests to pass
-log4j.logger.org.apache.tinkerpop.gremlin.util.Log4jRecordingAppenderTest=INFO
-
-# need to turn this on so that we know the test seed
-log4j.logger.org.apache.tinkerpop.gremlin.TestHelper=INFO
\ No newline at end of file
diff --git a/gremlin-test/src/test/resources/log4j-test.properties b/gremlin-test/src/test/resources/log4j-test.properties
deleted file mode 100644
index 0517b4c..0000000
--- a/gremlin-test/src/test/resources/log4j-test.properties
+++ /dev/null
@@ -1,27 +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.
-
-log4j.rootLogger=WARN, stdout
-log4j.appender.stdout=org.apache.log4j.ConsoleAppender
-log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
-log4j.appender.stdout.layout.ConversionPattern=[%p] %C - %m%n
-
-# need to turn this on as this test actually tests "logging" - needs INFO at minimum for tests to pass
-log4j.logger.org.apache.tinkerpop.gremlin.util.Log4jRecordingAppenderTest=INFO   
-
-# need to turn this on so that we know the test seed
-log4j.logger.org.apache.tinkerpop.gremlin.TestHelper=INFO
\ No newline at end of file
diff --git a/gremlin-test/src/test/resources/logback-silent.xml b/gremlin-test/src/test/resources/logback-silent.xml
new file mode 100644
index 0000000..cb9d252
--- /dev/null
+++ b/gremlin-test/src/test/resources/logback-silent.xml
@@ -0,0 +1,28 @@
+<!--
+Licensed to the Apache Software Foundation (ASF) under one or more
+contributor license agreements.  See the NOTICE file distributed with
+this work for additional information regarding copyright ownership.
+The ASF licenses this file to You under the Apache License, Version 2.0
+(the "License"); you may not use this file except in compliance with
+the License.  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+-->
+<configuration>
+    <appender name="stdout" class="ch.qos.logback.core.ConsoleAppender">
+        <encoder>
+            <pattern>[%p] %C - %m%n</pattern>
+        </encoder>
+    </appender>
+    <!-- need to turn this on so that we know the test seed -->
+    <logger name="org.apache.tinkerpop.gremlin.TestHelper" level="INFO"/>
+    <root level="OFF">
+        <appender-ref ref="stdout"/>
+    </root>
+</configuration>
\ No newline at end of file
diff --git a/gremlin-test/src/test/resources/logback-test.xml b/gremlin-test/src/test/resources/logback-test.xml
new file mode 100644
index 0000000..f1bca0d
--- /dev/null
+++ b/gremlin-test/src/test/resources/logback-test.xml
@@ -0,0 +1,28 @@
+<!--
+Licensed to the Apache Software Foundation (ASF) under one or more
+contributor license agreements.  See the NOTICE file distributed with
+this work for additional information regarding copyright ownership.
+The ASF licenses this file to You under the Apache License, Version 2.0
+(the "License"); you may not use this file except in compliance with
+the License.  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+-->
+<configuration>
+    <appender name="stdout" class="ch.qos.logback.core.ConsoleAppender">
+        <encoder>
+            <pattern>[%p] %C - %m%n</pattern>
+        </encoder>
+    </appender>
+    <!-- need to turn this on so that we know the test seed -->
+    <logger name="org.apache.tinkerpop.gremlin.TestHelper" level="INFO"/>
+    <root level="WARN">
+        <appender-ref ref="stdout"/>
+    </root>
+</configuration>
\ No newline at end of file
diff --git a/gremlin-tools/gremlin-benchmark/pom.xml b/gremlin-tools/gremlin-benchmark/pom.xml
index a350de4..676571a 100644
--- a/gremlin-tools/gremlin-benchmark/pom.xml
+++ b/gremlin-tools/gremlin-benchmark/pom.xml
@@ -76,13 +76,8 @@ limitations under the License.
             <scope>provided</scope>
         </dependency>
         <dependency>
-            <groupId>org.slf4j</groupId>
-            <artifactId>slf4j-log4j12</artifactId>
-        </dependency>
-        <dependency>
-            <groupId>log4j</groupId>
-            <artifactId>log4j</artifactId>
-            <optional>true</optional>
+            <groupId>ch.qos.logback</groupId>
+            <artifactId>logback-classic</artifactId>
         </dependency>
     </dependencies>
     <build>
@@ -109,7 +104,7 @@ limitations under the License.
                     </excludes>
                     <systemPropertyVariables>
                         <benchmarkReportDir>${project.build.directory}/reports/benchmark/</benchmarkReportDir>
-                        <jvmArgs>-Dlog4j.configuration=${log4j-test.properties} -server -Xms4g -Xmx4g -Xss4m</jvmArgs>
+                        <jvmArgs>-Dlogback.configurationFile=${logback-test.properties} -server -Xms4g -Xmx4g -Xss4m</jvmArgs>
                         <warmupIterations>3</warmupIterations>
                         <measureIterations>10</measureIterations>
                         <forks>2</forks>
diff --git a/gremlin-tools/gremlin-benchmark/src/test/resources/log4j-silent.properties b/gremlin-tools/gremlin-benchmark/src/test/resources/log4j-silent.properties
deleted file mode 100644
index 1825bb0..0000000
--- a/gremlin-tools/gremlin-benchmark/src/test/resources/log4j-silent.properties
+++ /dev/null
@@ -1,23 +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.
-
-# this file should always have logging set to OFF.  it seems, however, that an appender of some sort is
-# required or else some logs throw error and use other log4j.properties files on the path.
-log4j.rootLogger=OFF, stdout
-log4j.appender.stdout=org.apache.log4j.ConsoleAppender
-log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
-log4j.appender.stdout.layout.ConversionPattern=[%p] %C - %m%n
\ No newline at end of file
diff --git a/gremlin-tools/gremlin-benchmark/src/test/resources/log4j-test.properties b/gremlin-tools/gremlin-benchmark/src/test/resources/log4j-test.properties
deleted file mode 100644
index ef436fe..0000000
--- a/gremlin-tools/gremlin-benchmark/src/test/resources/log4j-test.properties
+++ /dev/null
@@ -1,21 +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.
-
-log4j.rootLogger=WARN, stdout
-log4j.appender.stdout=org.apache.log4j.ConsoleAppender
-log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
-log4j.appender.stdout.layout.ConversionPattern=[%p] %C - %m%n
\ No newline at end of file
diff --git a/gremlin-tools/gremlin-benchmark/src/test/resources/logback-silent.xml b/gremlin-tools/gremlin-benchmark/src/test/resources/logback-silent.xml
new file mode 100644
index 0000000..4c5947d
--- /dev/null
+++ b/gremlin-tools/gremlin-benchmark/src/test/resources/logback-silent.xml
@@ -0,0 +1,26 @@
+<!--
+Licensed to the Apache Software Foundation (ASF) under one or more
+contributor license agreements.  See the NOTICE file distributed with
+this work for additional information regarding copyright ownership.
+The ASF licenses this file to You under the Apache License, Version 2.0
+(the "License"); you may not use this file except in compliance with
+the License.  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+-->
+<configuration>
+    <appender name="stdout" class="ch.qos.logback.core.ConsoleAppender">
+        <encoder>
+            <pattern>[%p] %C - %m%n</pattern>
+        </encoder>
+    </appender>
+    <root level="OFF">
+        <appender-ref ref="stdout"/>
+    </root>
+</configuration>
\ No newline at end of file
diff --git a/gremlin-tools/gremlin-benchmark/src/test/resources/logback-test.xml b/gremlin-tools/gremlin-benchmark/src/test/resources/logback-test.xml
new file mode 100644
index 0000000..5d94c3b
--- /dev/null
+++ b/gremlin-tools/gremlin-benchmark/src/test/resources/logback-test.xml
@@ -0,0 +1,26 @@
+<!--
+Licensed to the Apache Software Foundation (ASF) under one or more
+contributor license agreements.  See the NOTICE file distributed with
+this work for additional information regarding copyright ownership.
+The ASF licenses this file to You under the Apache License, Version 2.0
+(the "License"); you may not use this file except in compliance with
+the License.  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+-->
+<configuration>
+    <appender name="stdout" class="ch.qos.logback.core.ConsoleAppender">
+        <encoder>
+            <pattern>[%p] %C - %m%n</pattern>
+        </encoder>
+    </appender>
+    <root level="WARN">
+        <appender-ref ref="stdout"/>
+    </root>
+</configuration>
\ No newline at end of file
diff --git a/gremlin-tools/gremlin-coverage/pom.xml b/gremlin-tools/gremlin-coverage/pom.xml
index f2bddd5..20c333e 100644
--- a/gremlin-tools/gremlin-coverage/pom.xml
+++ b/gremlin-tools/gremlin-coverage/pom.xml
@@ -47,9 +47,8 @@
             <version>${project.version}</version>
         </dependency>
         <dependency>
-            <groupId>org.slf4j</groupId>
-            <artifactId>slf4j-log4j12</artifactId>
-            <optional>true</optional>
+            <groupId>ch.qos.logback</groupId>
+            <artifactId>logback-classic</artifactId>
         </dependency>
     </dependencies>
 
diff --git a/gremlin-tools/gremlin-io-test/pom.xml b/gremlin-tools/gremlin-io-test/pom.xml
index ddd4498..999939e 100644
--- a/gremlin-tools/gremlin-io-test/pom.xml
+++ b/gremlin-tools/gremlin-io-test/pom.xml
@@ -45,9 +45,8 @@
             </exclusions>
         </dependency>
         <dependency>
-            <groupId>org.slf4j</groupId>
-            <artifactId>slf4j-log4j12</artifactId>
-            <optional>true</optional>
+            <groupId>ch.qos.logback</groupId>
+            <artifactId>logback-classic</artifactId>
         </dependency>
         <dependency>
             <groupId>org.apache.tinkerpop</groupId>
@@ -106,9 +105,9 @@
                                 <scope>runtime</scope>
                             </dependency>
                             <dependency>
-                                <groupId>log4j</groupId>
-                                <artifactId>log4j</artifactId>
-                                <version>1.2.17</version>
+                                <groupId>ch.qos.logback</groupId>
+                                <artifactId>logback-classic</artifactId>
+                                <version>${logback.version}</version>
                                 <scope>runtime</scope>
                             </dependency>
                         </dependencies>
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/log4j-silent.properties b/gremlin-tools/gremlin-io-test/src/test/resources/log4j-silent.properties
deleted file mode 100644
index 1825bb0..0000000
--- a/gremlin-tools/gremlin-io-test/src/test/resources/log4j-silent.properties
+++ /dev/null
@@ -1,23 +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.
-
-# this file should always have logging set to OFF.  it seems, however, that an appender of some sort is
-# required or else some logs throw error and use other log4j.properties files on the path.
-log4j.rootLogger=OFF, stdout
-log4j.appender.stdout=org.apache.log4j.ConsoleAppender
-log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
-log4j.appender.stdout.layout.ConversionPattern=[%p] %C - %m%n
\ No newline at end of file
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/log4j-test.properties b/gremlin-tools/gremlin-io-test/src/test/resources/log4j-test.properties
deleted file mode 100644
index ef436fe..0000000
--- a/gremlin-tools/gremlin-io-test/src/test/resources/log4j-test.properties
+++ /dev/null
@@ -1,21 +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.
-
-log4j.rootLogger=WARN, stdout
-log4j.appender.stdout=org.apache.log4j.ConsoleAppender
-log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
-log4j.appender.stdout.layout.ConversionPattern=[%p] %C - %m%n
\ No newline at end of file
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/logback-silent.xml b/gremlin-tools/gremlin-io-test/src/test/resources/logback-silent.xml
new file mode 100644
index 0000000..4c5947d
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/logback-silent.xml
@@ -0,0 +1,26 @@
+<!--
+Licensed to the Apache Software Foundation (ASF) under one or more
+contributor license agreements.  See the NOTICE file distributed with
+this work for additional information regarding copyright ownership.
+The ASF licenses this file to You under the Apache License, Version 2.0
+(the "License"); you may not use this file except in compliance with
+the License.  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+-->
+<configuration>
+    <appender name="stdout" class="ch.qos.logback.core.ConsoleAppender">
+        <encoder>
+            <pattern>[%p] %C - %m%n</pattern>
+        </encoder>
+    </appender>
+    <root level="OFF">
+        <appender-ref ref="stdout"/>
+    </root>
+</configuration>
\ No newline at end of file
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/logback-test.xml b/gremlin-tools/gremlin-io-test/src/test/resources/logback-test.xml
new file mode 100644
index 0000000..5d94c3b
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/logback-test.xml
@@ -0,0 +1,26 @@
+<!--
+Licensed to the Apache Software Foundation (ASF) under one or more
+contributor license agreements.  See the NOTICE file distributed with
+this work for additional information regarding copyright ownership.
+The ASF licenses this file to You under the Apache License, Version 2.0
+(the "License"); you may not use this file except in compliance with
+the License.  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+-->
+<configuration>
+    <appender name="stdout" class="ch.qos.logback.core.ConsoleAppender">
+        <encoder>
+            <pattern>[%p] %C - %m%n</pattern>
+        </encoder>
+    </appender>
+    <root level="WARN">
+        <appender-ref ref="stdout"/>
+    </root>
+</configuration>
\ No newline at end of file
diff --git a/hadoop-gremlin/pom.xml b/hadoop-gremlin/pom.xml
index f5b16b0..8fbd994 100644
--- a/hadoop-gremlin/pom.xml
+++ b/hadoop-gremlin/pom.xml
@@ -52,16 +52,12 @@ limitations under the License.
             <version>${hadoop.version}</version>
             <exclusions>
                 <exclusion>
-                    <groupId>log4j</groupId>
-                    <artifactId>log4j</artifactId>
-                </exclusion>
-                <exclusion>
                     <groupId>org.slf4j</groupId>
-                    <artifactId>slf4j-log4j12</artifactId>
+                    <artifactId>slf4j-api</artifactId>
                 </exclusion>
                 <exclusion>
                     <groupId>org.slf4j</groupId>
-                    <artifactId>slf4j-api</artifactId>
+                    <artifactId>slf4j-log4j12</artifactId>
                 </exclusion>
                 <exclusion>
                     <groupId>commons-codec</groupId>
@@ -107,6 +103,10 @@ limitations under the License.
                     <groupId>org.apache.commons</groupId>
                     <artifactId>commons-compress</artifactId>
                 </exclusion>
+                <exclusion>
+                    <groupId>log4j</groupId>
+                    <artifactId>log4j</artifactId>
+                </exclusion>
                 <!--
                 spark 3.0/scala 2.12 uses paranamer 2.8 and hadoop is stuck with an older version. without 2.8 you get
                 SPARK-14220
@@ -172,6 +172,12 @@ limitations under the License.
             <artifactId>commons-compress</artifactId>
             <version>1.19</version>
         </dependency>
+        <!-- log4j is required by hadoop -->
+        <dependency>
+            <groupId>log4j</groupId>
+            <artifactId>log4j</artifactId>
+            <version>1.2.17</version>
+        </dependency>
         <!-- TEST -->
         <dependency>
             <groupId>org.apache.tinkerpop</groupId>
@@ -186,8 +192,8 @@ limitations under the License.
             <scope>test</scope>
         </dependency>
         <dependency>
-            <groupId>org.slf4j</groupId>
-            <artifactId>slf4j-log4j12</artifactId>
+            <groupId>ch.qos.logback</groupId>
+            <artifactId>logback-classic</artifactId>
             <scope>test</scope>
         </dependency>
     </dependencies>
diff --git a/hadoop-gremlin/src/test/resources/log4j-silent.properties b/hadoop-gremlin/src/test/resources/log4j-silent.properties
deleted file mode 100644
index 4e9f465..0000000
--- a/hadoop-gremlin/src/test/resources/log4j-silent.properties
+++ /dev/null
@@ -1,26 +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.
-
-# this file should always have logging set to OFF.  it seems, however, that an appender of some sort is
-# required or else some logs throw error and use other log4j.properties files on the path.
-log4j.rootLogger=OFF, stdout
-log4j.appender.stdout=org.apache.log4j.ConsoleAppender
-log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
-log4j.appender.stdout.layout.ConversionPattern=[%p] %C - %m%n  
-
-# need to turn this on so that we know the test seed
-log4j.logger.org.apache.tinkerpop.gremlin.TestHelper=INFO
\ No newline at end of file
diff --git a/hadoop-gremlin/src/test/resources/log4j-test.properties b/hadoop-gremlin/src/test/resources/log4j-test.properties
deleted file mode 100644
index 7f7a284..0000000
--- a/hadoop-gremlin/src/test/resources/log4j-test.properties
+++ /dev/null
@@ -1,24 +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.
-
-log4j.rootLogger=WARN, stdout
-log4j.appender.stdout=org.apache.log4j.ConsoleAppender
-log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
-log4j.appender.stdout.layout.ConversionPattern=[%p] %C - %m%n   
-
-# need to turn this on so that we know the test seed
-log4j.logger.org.apache.tinkerpop.gremlin.TestHelper=INFO
diff --git a/hadoop-gremlin/src/test/resources/logback-silent.xml b/hadoop-gremlin/src/test/resources/logback-silent.xml
new file mode 100644
index 0000000..cb9d252
--- /dev/null
+++ b/hadoop-gremlin/src/test/resources/logback-silent.xml
@@ -0,0 +1,28 @@
+<!--
+Licensed to the Apache Software Foundation (ASF) under one or more
+contributor license agreements.  See the NOTICE file distributed with
+this work for additional information regarding copyright ownership.
+The ASF licenses this file to You under the Apache License, Version 2.0
+(the "License"); you may not use this file except in compliance with
+the License.  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+-->
+<configuration>
+    <appender name="stdout" class="ch.qos.logback.core.ConsoleAppender">
+        <encoder>
+            <pattern>[%p] %C - %m%n</pattern>
+        </encoder>
+    </appender>
+    <!-- need to turn this on so that we know the test seed -->
+    <logger name="org.apache.tinkerpop.gremlin.TestHelper" level="INFO"/>
+    <root level="OFF">
+        <appender-ref ref="stdout"/>
+    </root>
+</configuration>
\ No newline at end of file
diff --git a/hadoop-gremlin/src/test/resources/logback-test.xml b/hadoop-gremlin/src/test/resources/logback-test.xml
new file mode 100644
index 0000000..f1bca0d
--- /dev/null
+++ b/hadoop-gremlin/src/test/resources/logback-test.xml
@@ -0,0 +1,28 @@
+<!--
+Licensed to the Apache Software Foundation (ASF) under one or more
+contributor license agreements.  See the NOTICE file distributed with
+this work for additional information regarding copyright ownership.
+The ASF licenses this file to You under the Apache License, Version 2.0
+(the "License"); you may not use this file except in compliance with
+the License.  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+-->
+<configuration>
+    <appender name="stdout" class="ch.qos.logback.core.ConsoleAppender">
+        <encoder>
+            <pattern>[%p] %C - %m%n</pattern>
+        </encoder>
+    </appender>
+    <!-- need to turn this on so that we know the test seed -->
+    <logger name="org.apache.tinkerpop.gremlin.TestHelper" level="INFO"/>
+    <root level="WARN">
+        <appender-ref ref="stdout"/>
+    </root>
+</configuration>
\ No newline at end of file
diff --git a/neo4j-gremlin/pom.xml b/neo4j-gremlin/pom.xml
index 233cfa4..8a2b011 100644
--- a/neo4j-gremlin/pom.xml
+++ b/neo4j-gremlin/pom.xml
@@ -51,8 +51,8 @@ limitations under the License.
             </exclusions>
         </dependency>
         <dependency>
-            <groupId>org.slf4j</groupId>
-            <artifactId>slf4j-log4j12</artifactId>
+            <groupId>ch.qos.logback</groupId>
+            <artifactId>logback-classic</artifactId>
             <scope>test</scope>
         </dependency>
     </dependencies>
diff --git a/neo4j-gremlin/src/test/resources/log4j-silent.properties b/neo4j-gremlin/src/test/resources/log4j-silent.properties
deleted file mode 100644
index 7c312f7..0000000
--- a/neo4j-gremlin/src/test/resources/log4j-silent.properties
+++ /dev/null
@@ -1,26 +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.
-
-# this file should always have logging set to OFF.  it seems, however, that an appender of some sort is
-# required or else some logs throw error and use other log4j.properties files on the path.
-log4j.rootLogger=OFF, stdout
-log4j.appender.stdout=org.apache.log4j.ConsoleAppender
-log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
-log4j.appender.stdout.layout.ConversionPattern=[%p] %C - %m%n
-
-# need to turn this on so that we know the test seed
-log4j.logger.org.apache.tinkerpop.gremlin.TestHelper=INFO
\ No newline at end of file
diff --git a/neo4j-gremlin/src/test/resources/log4j-test.properties b/neo4j-gremlin/src/test/resources/log4j-test.properties
deleted file mode 100644
index 067fa7b..0000000
--- a/neo4j-gremlin/src/test/resources/log4j-test.properties
+++ /dev/null
@@ -1,24 +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.
-
-log4j.rootLogger=WARN, stdout
-log4j.appender.stdout=org.apache.log4j.ConsoleAppender
-log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
-log4j.appender.stdout.layout.ConversionPattern=[%p] %C - %m%n
-
-# need to turn this on so that we know the test seed
-log4j.logger.org.apache.tinkerpop.gremlin.TestHelper=INFO
\ No newline at end of file
diff --git a/neo4j-gremlin/src/test/resources/logback-silent.xml b/neo4j-gremlin/src/test/resources/logback-silent.xml
new file mode 100644
index 0000000..cb9d252
--- /dev/null
+++ b/neo4j-gremlin/src/test/resources/logback-silent.xml
@@ -0,0 +1,28 @@
+<!--
+Licensed to the Apache Software Foundation (ASF) under one or more
+contributor license agreements.  See the NOTICE file distributed with
+this work for additional information regarding copyright ownership.
+The ASF licenses this file to You under the Apache License, Version 2.0
+(the "License"); you may not use this file except in compliance with
+the License.  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+-->
+<configuration>
+    <appender name="stdout" class="ch.qos.logback.core.ConsoleAppender">
+        <encoder>
+            <pattern>[%p] %C - %m%n</pattern>
+        </encoder>
+    </appender>
+    <!-- need to turn this on so that we know the test seed -->
+    <logger name="org.apache.tinkerpop.gremlin.TestHelper" level="INFO"/>
+    <root level="OFF">
+        <appender-ref ref="stdout"/>
+    </root>
+</configuration>
\ No newline at end of file
diff --git a/neo4j-gremlin/src/test/resources/logback-test.xml b/neo4j-gremlin/src/test/resources/logback-test.xml
new file mode 100644
index 0000000..f1bca0d
--- /dev/null
+++ b/neo4j-gremlin/src/test/resources/logback-test.xml
@@ -0,0 +1,28 @@
+<!--
+Licensed to the Apache Software Foundation (ASF) under one or more
+contributor license agreements.  See the NOTICE file distributed with
+this work for additional information regarding copyright ownership.
+The ASF licenses this file to You under the Apache License, Version 2.0
+(the "License"); you may not use this file except in compliance with
+the License.  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+-->
+<configuration>
+    <appender name="stdout" class="ch.qos.logback.core.ConsoleAppender">
+        <encoder>
+            <pattern>[%p] %C - %m%n</pattern>
+        </encoder>
+    </appender>
+    <!-- need to turn this on so that we know the test seed -->
+    <logger name="org.apache.tinkerpop.gremlin.TestHelper" level="INFO"/>
+    <root level="WARN">
+        <appender-ref ref="stdout"/>
+    </root>
+</configuration>
\ No newline at end of file
diff --git a/pom.xml b/pom.xml
index 8a85949..7b9b401 100644
--- a/pom.xml
+++ b/pom.xml
@@ -157,7 +157,7 @@ limitations under the License.
         <java.tuples.version>1.2</java.tuples.version>
         <javadoc-plugin.version>3.1.0</javadoc-plugin.version>
         <jcabi.version>1.1</jcabi.version>
-        <log4j.version>1.2.17</log4j.version>
+        <logback.version>1.2.3</logback.version>
         <metrics.version>3.0.2</metrics.version>
         <netty.version>4.1.61.Final</netty.version>
         <slf4j.version>1.7.25</slf4j.version>
@@ -171,12 +171,12 @@ limitations under the License.
         <suresafeArgs> </suresafeArgs>
 
         <!--
-        This file will come from the root of each modules test/resources/ directories. log4j-silent.properties will
-        turn off all logging possible while still allowing tests to pass. log4j-test.properties will be more verbose
+        This file will come from the root of each modules test/resources/ directories. logback-silent.xml will
+        turn off all logging possible while still allowing tests to pass. logback-test.xml will be more verbose
         in its output.
         -->
-        <log4j-test.properties>file:target/test-classes/log4j-test.properties</log4j-test.properties>
-        <log4j-silent.properties>file:target/test-classes/log4j-silent.properties</log4j-silent.properties>
+        <logback-test.properties>file:target/test-classes/logback-test.xml</logback-test.properties>
+        <logback-silent.properties>file:target/test-classes/logback-silent.xml</logback-silent.properties>
 
         <muteTestLogs>false</muteTestLogs>
     </properties>
@@ -488,7 +488,8 @@ limitations under the License.
                     <version>2.21.0</version>
                     <configuration>
                         <argLine>
-                            -Dlog4j.configuration=${log4j-test.properties} -Dbuild.dir=${project.build.directory} -Dis.testing=true -Djava.net.preferIPv4Stack=true ${suresafeArgs}
+                            -Dlogback.configurationFile=${logback-test.properties} -Dbuild.dir=${project.build.directory}
+                            -Dis.testing=true -Djava.net.preferIPv4Stack=true ${suresafeArgs}
                         </argLine>
                         <trimStackTrace>false</trimStackTrace>
                         <excludes>
@@ -512,7 +513,9 @@ limitations under the License.
                                 </includes>
                                 <skipTests>${skipIntegrationTests}</skipTests>
                                 <argLine>
-                                    -Dlog4j.configuration=${log4j-test.properties} -Dhost=localhost -Dport=8182 -Dbuild.dir=${project.build.directory} -Dis.testing=true -Djava.net.preferIPv4Stack=true ${suresafeArgs}
+                                    -Dlogback.configuration=${logback-test.properties} -Dhost=localhost -Dport=8182
+                                    -Dbuild.dir=${project.build.directory} -Dis.testing=true
+                                    -Djava.net.preferIPv4Stack=true ${suresafeArgs}
                                 </argLine>
                                 <forkCount>1</forkCount>
                                 <reuseForks>false</reuseForks>
@@ -733,11 +736,6 @@ limitations under the License.
                 </exclusions>
             </dependency>
             <dependency>
-                <groupId>log4j</groupId>
-                <artifactId>log4j</artifactId>
-                <version>${log4j.version}</version>
-            </dependency>
-            <dependency>
                 <groupId>junit</groupId>
                 <artifactId>junit</artifactId>
                 <version>4.13.1</version>
@@ -804,9 +802,14 @@ limitations under the License.
                 <version>2.2</version>
             </dependency>
             <dependency>
-                <groupId>org.slf4j</groupId>
-                <artifactId>slf4j-log4j12</artifactId>
-                <version>${slf4j.version}</version>
+                <groupId>io.github.hakky54</groupId>
+                <artifactId>logcaptor</artifactId>
+                <version>2.6.1</version>
+            </dependency>
+            <dependency>
+                <groupId>ch.qos.logback</groupId>
+                <artifactId>logback-classic</artifactId>
+                <version>${logback.version}</version>
             </dependency>
             <dependency>
                 <groupId>org.slf4j</groupId>
@@ -1536,7 +1539,10 @@ limitations under the License.
                         <groupId>org.apache.maven.plugins</groupId>
                         <artifactId>maven-surefire-plugin</artifactId>
                         <configuration>
-                            <argLine>-Dlog4j.configuration=${log4j-silent.properties} -Dbuild.dir=${project.build.directory} -Dis.testing=true -Djava.net.preferIPv4Stack=true ${suresafeArgs}
+                            <argLine>
+                                -Dlogback.configurationFile=${logback-silent.properties}
+                                -Dbuild.dir=${project.build.directory} -Dis.testing=true
+                                -Djava.net.preferIPv4Stack=true ${suresafeArgs}
                             </argLine>
                             <excludes>
                                 <exclude>**/*IntegrateTest.java</exclude>
@@ -1633,7 +1639,9 @@ limitations under the License.
                         <groupId>org.apache.maven.plugins</groupId>
                         <artifactId>maven-surefire-plugin</artifactId>
                         <configuration>
-                            <argLine>-Dlog4j.configuration=${log4j-test.properties} -Dbuild.dir=${project.build.directory} -Dis.testing=true ${suresafeArgs} -Djava.net.preferIPv4Stack=true
+                            <argLine>-Dlogback.configuration=${logback-test.properties}
+                                -Dbuild.dir=${project.build.directory} -Dis.testing=true ${suresafeArgs}
+                                -Djava.net.preferIPv4Stack=true
                             </argLine>
                         </configuration>
                     </plugin>
@@ -1641,7 +1649,9 @@ limitations under the License.
                         <groupId>org.apache.maven.plugins</groupId>
                         <artifactId>maven-failsafe-plugin</artifactId>
                         <configuration>
-                            <argLine>-Dlog4j.configuration=${log4j-test.properties} -Dhost=localhost -Dport=8182 -Dbuild.dir=${project.build.directory} -Dis.testing=true ${suresafeArgs} -Djava.net.preferIPv4Stack=true
+                            <argLine>-Dlogback.configuration=${logback-test.properties} -Dhost=localhost -Dport=8182
+                                -Dbuild.dir=${project.build.directory} -Dis.testing=true ${suresafeArgs}
+                                -Djava.net.preferIPv4Stack=true
                             </argLine>
                         </configuration>
                     </plugin>
diff --git a/spark-gremlin/pom.xml b/spark-gremlin/pom.xml
index c8d5f4c..e1f69c1 100644
--- a/spark-gremlin/pom.xml
+++ b/spark-gremlin/pom.xml
@@ -88,6 +88,10 @@
             <version>${spark.version}</version>
             <exclusions>
                 <exclusion>
+                    <groupId>org.slf4j</groupId>
+                    <artifactId>slf4j-log4j12</artifactId>
+                </exclusion>
+                <exclusion>
                     <groupId>org.apache.hadoop</groupId>
                     <artifactId>hadoop-client</artifactId>
                 </exclusion>
@@ -170,6 +174,14 @@
                     <groupId>jline</groupId>
                     <artifactId>jline</artifactId>
                 </exclusion>
+                <exclusion>
+                    <groupId>log4j</groupId>
+                    <artifactId>log4j</artifactId>
+                </exclusion>
+                <exclusion>
+                    <groupId>org.slf4j</groupId>
+                    <artifactId>slf4j-log4j12</artifactId>
+                </exclusion>
             </exclusions>
         </dependency>
         <!-- TEST -->
@@ -186,8 +198,8 @@
             <scope>test</scope>
         </dependency>
         <dependency>
-            <groupId>org.slf4j</groupId>
-            <artifactId>slf4j-log4j12</artifactId>
+            <groupId>ch.qos.logback</groupId>
+            <artifactId>logback-classic</artifactId>
             <scope>test</scope>
         </dependency>
     </dependencies>
diff --git a/spark-gremlin/src/test/resources/log4j-silent.properties b/spark-gremlin/src/test/resources/log4j-silent.properties
deleted file mode 100644
index 7c312f7..0000000
--- a/spark-gremlin/src/test/resources/log4j-silent.properties
+++ /dev/null
@@ -1,26 +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.
-
-# this file should always have logging set to OFF.  it seems, however, that an appender of some sort is
-# required or else some logs throw error and use other log4j.properties files on the path.
-log4j.rootLogger=OFF, stdout
-log4j.appender.stdout=org.apache.log4j.ConsoleAppender
-log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
-log4j.appender.stdout.layout.ConversionPattern=[%p] %C - %m%n
-
-# need to turn this on so that we know the test seed
-log4j.logger.org.apache.tinkerpop.gremlin.TestHelper=INFO
\ No newline at end of file
diff --git a/spark-gremlin/src/test/resources/log4j-test.properties b/spark-gremlin/src/test/resources/log4j-test.properties
deleted file mode 100644
index 1a84d2c..0000000
--- a/spark-gremlin/src/test/resources/log4j-test.properties
+++ /dev/null
@@ -1,28 +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.
-
-log4j.rootLogger=WARN, stdout
-log4j.appender.stdout=org.apache.log4j.ConsoleAppender
-log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
-log4j.appender.stdout.layout.ConversionPattern=[%p] %C - %m%n
-
-log4j.logger.org.apache.spark=ERROR
-log4j.logger.org.spark-project=ERROR
-log4j.logger.org.apache.hadoop=ERROR
-
-# need to turn this on so that we know the test seed
-log4j.logger.org.apache.tinkerpop.gremlin.TestHelper=INFO
\ No newline at end of file
diff --git a/spark-gremlin/src/test/resources/logback-silent.xml b/spark-gremlin/src/test/resources/logback-silent.xml
new file mode 100644
index 0000000..cb9d252
--- /dev/null
+++ b/spark-gremlin/src/test/resources/logback-silent.xml
@@ -0,0 +1,28 @@
+<!--
+Licensed to the Apache Software Foundation (ASF) under one or more
+contributor license agreements.  See the NOTICE file distributed with
+this work for additional information regarding copyright ownership.
+The ASF licenses this file to You under the Apache License, Version 2.0
+(the "License"); you may not use this file except in compliance with
+the License.  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+-->
+<configuration>
+    <appender name="stdout" class="ch.qos.logback.core.ConsoleAppender">
+        <encoder>
+            <pattern>[%p] %C - %m%n</pattern>
+        </encoder>
+    </appender>
+    <!-- need to turn this on so that we know the test seed -->
+    <logger name="org.apache.tinkerpop.gremlin.TestHelper" level="INFO"/>
+    <root level="OFF">
+        <appender-ref ref="stdout"/>
+    </root>
+</configuration>
\ No newline at end of file
diff --git a/spark-gremlin/src/test/resources/logback-test.xml b/spark-gremlin/src/test/resources/logback-test.xml
new file mode 100644
index 0000000..257d1f1
--- /dev/null
+++ b/spark-gremlin/src/test/resources/logback-test.xml
@@ -0,0 +1,30 @@
+<!--
+Licensed to the Apache Software Foundation (ASF) under one or more
+contributor license agreements.  See the NOTICE file distributed with
+this work for additional information regarding copyright ownership.
+The ASF licenses this file to You under the Apache License, Version 2.0
+(the "License"); you may not use this file except in compliance with
+the License.  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+-->
+<configuration>
+    <appender name="stdout" class="ch.qos.logback.core.ConsoleAppender">
+        <encoder>
+            <pattern>[%p] %C - %m%n</pattern>
+        </encoder>
+    </appender>
+    <logger name="org.apache.spark" level="ERROR"/>
+    <logger name="org.apache.hadoop" level="ERROR"/>
+    <logger name="org.spark-project" level="ERROR"/>
+    <logger name="org.apache.tinkerpop.gremlin.TestHelper" level="INFO"/>
+    <root level="WARN">
+        <appender-ref ref="stdout"/>
+    </root>
+</configuration>
\ No newline at end of file
diff --git a/sparql-gremlin/pom.xml b/sparql-gremlin/pom.xml
index 595ec9f..466867c 100644
--- a/sparql-gremlin/pom.xml
+++ b/sparql-gremlin/pom.xml
@@ -24,8 +24,8 @@
             <version>${project.version}</version>
         </dependency>
         <dependency>
-            <groupId>org.slf4j</groupId>
-            <artifactId>slf4j-log4j12</artifactId>
+            <groupId>ch.qos.logback</groupId>
+            <artifactId>logback-classic</artifactId>
             <scope>test</scope>
         </dependency>
         <dependency>
diff --git a/sparql-gremlin/src/test/resources/log4j-silent.properties b/sparql-gremlin/src/test/resources/log4j-silent.properties
deleted file mode 100644
index 1825bb0..0000000
--- a/sparql-gremlin/src/test/resources/log4j-silent.properties
+++ /dev/null
@@ -1,23 +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.
-
-# this file should always have logging set to OFF.  it seems, however, that an appender of some sort is
-# required or else some logs throw error and use other log4j.properties files on the path.
-log4j.rootLogger=OFF, stdout
-log4j.appender.stdout=org.apache.log4j.ConsoleAppender
-log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
-log4j.appender.stdout.layout.ConversionPattern=[%p] %C - %m%n
\ No newline at end of file
diff --git a/sparql-gremlin/src/test/resources/log4j-test.properties b/sparql-gremlin/src/test/resources/log4j-test.properties
deleted file mode 100644
index 79038b1..0000000
--- a/sparql-gremlin/src/test/resources/log4j-test.properties
+++ /dev/null
@@ -1,23 +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.
-#
-
-log4j.rootLogger=WARN, stdout
-log4j.appender.stdout=org.apache.log4j.ConsoleAppender
-log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
-log4j.appender.stdout.layout.ConversionPattern=[%p] %C - %m%n
\ No newline at end of file
diff --git a/sparql-gremlin/src/test/resources/logback-silent.xml b/sparql-gremlin/src/test/resources/logback-silent.xml
new file mode 100644
index 0000000..4c5947d
--- /dev/null
+++ b/sparql-gremlin/src/test/resources/logback-silent.xml
@@ -0,0 +1,26 @@
+<!--
+Licensed to the Apache Software Foundation (ASF) under one or more
+contributor license agreements.  See the NOTICE file distributed with
+this work for additional information regarding copyright ownership.
+The ASF licenses this file to You under the Apache License, Version 2.0
+(the "License"); you may not use this file except in compliance with
+the License.  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+-->
+<configuration>
+    <appender name="stdout" class="ch.qos.logback.core.ConsoleAppender">
+        <encoder>
+            <pattern>[%p] %C - %m%n</pattern>
+        </encoder>
+    </appender>
+    <root level="OFF">
+        <appender-ref ref="stdout"/>
+    </root>
+</configuration>
\ No newline at end of file
diff --git a/sparql-gremlin/src/test/resources/logback-test.xml b/sparql-gremlin/src/test/resources/logback-test.xml
new file mode 100644
index 0000000..5d94c3b
--- /dev/null
+++ b/sparql-gremlin/src/test/resources/logback-test.xml
@@ -0,0 +1,26 @@
+<!--
+Licensed to the Apache Software Foundation (ASF) under one or more
+contributor license agreements.  See the NOTICE file distributed with
+this work for additional information regarding copyright ownership.
+The ASF licenses this file to You under the Apache License, Version 2.0
+(the "License"); you may not use this file except in compliance with
+the License.  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+-->
+<configuration>
+    <appender name="stdout" class="ch.qos.logback.core.ConsoleAppender">
+        <encoder>
+            <pattern>[%p] %C - %m%n</pattern>
+        </encoder>
+    </appender>
+    <root level="WARN">
+        <appender-ref ref="stdout"/>
+    </root>
+</configuration>
\ No newline at end of file
diff --git a/tinkergraph-gremlin/pom.xml b/tinkergraph-gremlin/pom.xml
index 2ac8450..3f31389 100644
--- a/tinkergraph-gremlin/pom.xml
+++ b/tinkergraph-gremlin/pom.xml
@@ -36,8 +36,8 @@ limitations under the License.
             <artifactId>commons-lang3</artifactId>
         </dependency>
         <dependency>
-            <groupId>org.slf4j</groupId>
-            <artifactId>slf4j-log4j12</artifactId>
+            <groupId>ch.qos.logback</groupId>
+            <artifactId>logback-classic</artifactId>
             <scope>test</scope>
         </dependency>
         <dependency>
diff --git a/tinkergraph-gremlin/src/test/resources/log4j-silent.properties b/tinkergraph-gremlin/src/test/resources/log4j-silent.properties
deleted file mode 100644
index 7c312f7..0000000
--- a/tinkergraph-gremlin/src/test/resources/log4j-silent.properties
+++ /dev/null
@@ -1,26 +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.
-
-# this file should always have logging set to OFF.  it seems, however, that an appender of some sort is
-# required or else some logs throw error and use other log4j.properties files on the path.
-log4j.rootLogger=OFF, stdout
-log4j.appender.stdout=org.apache.log4j.ConsoleAppender
-log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
-log4j.appender.stdout.layout.ConversionPattern=[%p] %C - %m%n
-
-# need to turn this on so that we know the test seed
-log4j.logger.org.apache.tinkerpop.gremlin.TestHelper=INFO
\ No newline at end of file
diff --git a/tinkergraph-gremlin/src/test/resources/log4j-test.properties b/tinkergraph-gremlin/src/test/resources/log4j-test.properties
deleted file mode 100644
index 067fa7b..0000000
--- a/tinkergraph-gremlin/src/test/resources/log4j-test.properties
+++ /dev/null
@@ -1,24 +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.
-
-log4j.rootLogger=WARN, stdout
-log4j.appender.stdout=org.apache.log4j.ConsoleAppender
-log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
-log4j.appender.stdout.layout.ConversionPattern=[%p] %C - %m%n
-
-# need to turn this on so that we know the test seed
-log4j.logger.org.apache.tinkerpop.gremlin.TestHelper=INFO
\ No newline at end of file
diff --git a/tinkergraph-gremlin/src/test/resources/logback-silent.xml b/tinkergraph-gremlin/src/test/resources/logback-silent.xml
new file mode 100644
index 0000000..cb9d252
--- /dev/null
+++ b/tinkergraph-gremlin/src/test/resources/logback-silent.xml
@@ -0,0 +1,28 @@
+<!--
+Licensed to the Apache Software Foundation (ASF) under one or more
+contributor license agreements.  See the NOTICE file distributed with
+this work for additional information regarding copyright ownership.
+The ASF licenses this file to You under the Apache License, Version 2.0
+(the "License"); you may not use this file except in compliance with
+the License.  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+-->
+<configuration>
+    <appender name="stdout" class="ch.qos.logback.core.ConsoleAppender">
+        <encoder>
+            <pattern>[%p] %C - %m%n</pattern>
+        </encoder>
+    </appender>
+    <!-- need to turn this on so that we know the test seed -->
+    <logger name="org.apache.tinkerpop.gremlin.TestHelper" level="INFO"/>
+    <root level="OFF">
+        <appender-ref ref="stdout"/>
+    </root>
+</configuration>
\ No newline at end of file
diff --git a/tinkergraph-gremlin/src/test/resources/logback-test.xml b/tinkergraph-gremlin/src/test/resources/logback-test.xml
new file mode 100644
index 0000000..f1bca0d
--- /dev/null
+++ b/tinkergraph-gremlin/src/test/resources/logback-test.xml
@@ -0,0 +1,28 @@
+<!--
+Licensed to the Apache Software Foundation (ASF) under one or more
+contributor license agreements.  See the NOTICE file distributed with
+this work for additional information regarding copyright ownership.
+The ASF licenses this file to You under the Apache License, Version 2.0
+(the "License"); you may not use this file except in compliance with
+the License.  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+-->
+<configuration>
+    <appender name="stdout" class="ch.qos.logback.core.ConsoleAppender">
+        <encoder>
+            <pattern>[%p] %C - %m%n</pattern>
+        </encoder>
+    </appender>
+    <!-- need to turn this on so that we know the test seed -->
+    <logger name="org.apache.tinkerpop.gremlin.TestHelper" level="INFO"/>
+    <root level="WARN">
+        <appender-ref ref="stdout"/>
+    </root>
+</configuration>
\ No newline at end of file