Use Log4j 2 for logging

This removes the POILogger and POILogFactory mechanism for logging. This mechanism was created at a time when the Java landscape looked very different than it does today.

Log4j 2 is an Apache Foundation project that is well maintained and is widely regarded as having good performance and capabilities. We use only the Log4j API artifact. This lets application developers choose how they want to capture logging events if at all. Integrations with Log4j 2 Core and Logback are available from the Log4j project.

git-svn-id: https://svn.apache.org/repos/asf/poi/branches/log4j@1886103 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/.classpath b/.classpath
index d11178b..2943da6 100644
--- a/.classpath
+++ b/.classpath
@@ -25,7 +25,7 @@
 	<classpathentry kind="lib" path="lib/main-tests/jmh-core-1.26.jar"/>
 	<classpathentry kind="lib" path="lib/main-tests/jmh-generator-annprocess-1.26.jar"/>
 	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/>
-	<classpathentry exported="true" kind="lib" path="compile-lib/slf4j-api-1.7.30.jar"/>
+	<classpathentry exported="true" kind="lib" path="compile-lib/log4j-api-2.14.0.jar"/>
 	<classpathentry kind="lib" path="lib/ooxml-provided/bcpkix-jdk15on-1.67.jar"/>
 	<classpathentry kind="lib" path="lib/ooxml-provided/bcprov-jdk15on-1.67.jar"/>
 	<classpathentry kind="lib" path="lib/ooxml-tests/reflections-0.9.12.jar"/>
@@ -34,7 +34,6 @@
 	<classpathentry kind="lib" path="lib/ooxml-tests/log4j-1.2.17.jar"/>
 	<classpathentry exported="true" kind="lib" path="lib/ooxml-provided/xmlsec-2.2.0.jar"/>
 	<classpathentry exported="true" kind="lib" path="lib/commons-codec-1.15.jar"/>
-	<classpathentry exported="true" kind="lib" path="lib/commons-logging-1.2.jar"/>
 	<classpathentry exported="true" kind="lib" path="lib/commons-collections4-4.4.jar"/>
 	<classpathentry kind="lib" path="lib/commons-math3-3.6.1.jar"/>
 	<classpathentry kind="lib" path="lib/main-tests/xmlunit-core-2.8.0.jar"/>
diff --git a/build.gradle b/build.gradle
index 6a09be9..09ceae6 100644
--- a/build.gradle
+++ b/build.gradle
@@ -116,9 +116,9 @@
         commonsMathVersion = '3.6.1'
         japicmpversion = '5.0.0'
         junitVersion = '5.7.0'
+        log4jVersion = '2.14.0'
         mockitoVersion = '3.6.0'
         hamcrestVersion = '2.2'
-        slf4jVersion = '1.7.30'
         xmlbeansVersion = '4.0.0'
     }
 
@@ -140,6 +140,7 @@
         testCompile "org.junit.jupiter:junit-jupiter:${junitVersion}"
         testCompile "org.mockito:mockito-core:${mockitoVersion}"
         testCompile "org.hamcrest:hamcrest:${hamcrestVersion}"
+        testImplementation "org.apache.logging.log4j:log4j-core:${log4jVersion}"
     }
 
     jar {
@@ -179,6 +180,7 @@
         systemProperties['user.dir'] = workingDir
 
         systemProperties['POI.testdata.path'] = '../../test-data'
+        systemProperties['log4j.configurationFile'] = rootProject.file('log4j2-no-logging.xml')
 
         // this is necessary for JDK 9+ to keep formatting dates the same way as in previous JDK-versions
         systemProperties['java.locale.providers'] = 'JRE,CLDR'
@@ -235,15 +237,13 @@
 
     dependencies {
         compile "commons-codec:commons-codec:${commonsCodecVersion}"
-        compile 'commons-logging:commons-logging:1.2'
         compile 'org.apache.commons:commons-collections4:4.4'
         compile "org.apache.commons:commons-math3:${commonsMathVersion}"
-        compile "org.slf4j:slf4j-api:${slf4jVersion}"
+        implementation "org.apache.logging.log4j:log4j-api:${log4jVersion}"
         compile 'javax.activation:activation:1.1.1'
         compile 'com.zaxxer:SparseBitSet:1.2'
 
         testCompile 'org.reflections:reflections:0.9.12'
-        testRuntime "org.slf4j:slf4j-simple:${slf4jVersion}"
     }
 
     jar {
@@ -309,6 +309,7 @@
         compile "org.bouncycastle:bcpkix-jdk15on:${bouncyCastleVersion}"
         compile 'com.github.virtuald:curvesapi:1.06'
         compile 'com.zaxxer:SparseBitSet:1.2'
+        implementation "org.apache.logging.log4j:log4j-api:${log4jVersion}"
 
         // compile only, don't add it to our dist as it blows up the size
         compile 'org.apache.xmlgraphics:batik-all:1.13'
@@ -357,6 +358,7 @@
         compile project(':scratchpad')
 
         compile "org.apache.xmlbeans:xmlbeans:${xmlbeansVersion}"
+        implementation "org.apache.logging.log4j:log4j-core:${log4jVersion}"
 
         compile files("../../build/dist/maven/poi-ooxml-full/poi-ooxml-full-${version}.jar")
         compile "org.apache.commons:commons-compress:${commonsCompressVersion}"
@@ -437,6 +439,7 @@
         compile project(':main')
         compile "commons-codec:commons-codec:${commonsCodecVersion}"
         compile "org.apache.commons:commons-math3:${commonsMathVersion}"
+        implementation "org.apache.logging.log4j:log4j-api:${log4jVersion}"
 
         // cyclic-dependency here: compile project(':ooxml')
 
diff --git a/build.xml b/build.xml
index 4b315b1..1d9c209 100644
--- a/build.xml
+++ b/build.xml
@@ -84,9 +84,9 @@
 
     <!--
         Logging is suppressed by default.
-        To redirect log output to console, run ant with -Dorg.apache.poi.util.POILogger=org.apache.poi.util.SystemOutLogger
+        To redirect log output to console, run ant with -Dlog4j.configurationFile=log4j2-console.xml
     -->
-    <property name="org.apache.poi.util.POILogger" value="org.apache.poi.util.NullLogger"/>
+    <property name="log4j.configurationFile" value="log4j2-no-logging.xml"/>
 
     <!-- issue warnings if source code contains unmappable characters for encoding ASCII  -->
     <property name="java.source.encoding" value="UTF-8"/>
@@ -264,12 +264,11 @@
 
 
     <!-- jars in the /lib directory, see the fetch-jars target-->
-    <dependency prefix="main.commons-logging" artifact="org.slf4j:jcl-over-slf4j:1.7.30" usage="main"/>
     <dependency prefix="main.commons-codec" artifact="commons-codec:commons-codec:1.15" usage="main"/>
     <dependency prefix="main.commons-collections4" artifact="org.apache.commons:commons-collections4:4.4" usage="main"/>
     <dependency prefix="main.commons-math3" artifact="org.apache.commons:commons-math3:3.6.1" usage="main"/>
     <dependency prefix="main.com.zaxxer" artifact="com.zaxxer:SparseBitSet:1.2" usage="main"/>
-    <dependency prefix="main.slf4j-api" artifact="org.slf4j:slf4j-api:1.7.30" usage="main"/>
+    <dependency prefix="main.log4j-api" artifact="org.apache.logging.log4j:log4j-api:2.14.0" usage="main"/>
 
     <dependency prefix="main.junit-api" artifact="org.junit.jupiter:junit-jupiter-api:5.7.0" usage="main-tests"/>
     <dependency prefix="main.junit-jengine" artifact="org.junit.jupiter:junit-jupiter-engine:5.7.0" usage="main-tests"/>
@@ -289,7 +288,7 @@
     <dependency prefix="main.byte-buddy" artifact="net.bytebuddy:byte-buddy:1.10.19" usage="main-tests"/>
     <dependency prefix="main.byte-buddy-agent" artifact="net.bytebuddy:byte-buddy-agent:1.10.19" usage="main-tests"/>
     <dependency prefix="main.objenesis" artifact="org.objenesis:objenesis:3.1" usage="main-tests"/>
-    <dependency prefix="main.slf4j-simple" artifact="org.slf4j:slf4j-simple:1.7.30" usage="main-tests"/>
+    <dependency prefix="main.log4j-core" artifact="org.apache.logging.log4j:log4j-core:2.14.0" usage="main-tests"/>
 
     <dependency prefix="main.ant" artifact="org.apache.ant:ant:1.10.9" usage="excelant"/>
     <dependency prefix="main.antlauncher" artifact="org.apache.ant:ant-launcher:1.10.9" usage="excelant"/>
@@ -347,7 +346,7 @@
     <!-- Coverage -->
     <property name="coverage.dir" value="build/coverage"/>
     <!-- Exclude some uninteresting classes from coverage-instrumentation as we do not want to measure coverage in those packages anyway -->
-    <property name="coverage.excludes" value="org.openxmlformats.*:com.*:org.junit.*:junit.*:org.etsi.*:org.w3.*:org.slf4j.*:org.hamcrest.*:org.bouncycastle.*:org.apache.xmlbeans.*:org.apache.tools.*:org.apache.commons.*:org.apache.jcp.*:sun.*:schemaorg_apache_xmlbeans.*"/>
+    <property name="coverage.excludes" value="org.openxmlformats.*:com.*:org.junit.*:junit.*:org.etsi.*:org.w3.*:org.apache.logging.log4j.*:org.hamcrest.*:org.bouncycastle.*:org.apache.xmlbeans.*:org.apache.tools.*:org.apache.commons.*:org.apache.jcp.*:sun.*:schemaorg_apache_xmlbeans.*"/>
 
     <property name="file.leak.detector" value="-Dthis.is.a.dummy=true"/>
 
@@ -394,13 +393,12 @@
     <propertyset id="junit.properties">
         <propertyref name="POI.testdata.path"/>
         <propertyref name="java.awt.headless"/>
-        <propertyref name="org.apache.poi.util.POILogger"/>
+        <propertyref name="log4j.configurationFile"/>
         <propertyref name="http_proxy"/>
         <propertyref name="additionaljar"/>
         <propertyref name="user.language"/>
         <propertyref name="user.country"/>
         <propertyref name="javax.xml.stream.XMLInputFactory"/>
-        <propertyref name="org.apache.commons.logging.Log"/>
         <!-- required for Java 9 compilation -->
         <propertyref name="java.locale.providers"/>
         <!-- to detect if we are running on slow Gump VM -->
@@ -409,11 +407,11 @@
     </propertyset>
 
     <path id="main.classpath">
-        <pathelement location="${main.commons-logging.jar}"/>
         <pathelement location="${main.commons-codec.jar}"/>
         <pathelement location="${main.commons-collections4.jar}"/>
         <pathelement location="${main.commons-math3.jar}"/>
         <pathelement location="${main.com.zaxxer.jar}"/>
+        <pathelement location="${main.log4j-api.jar}"/>
     </path>
 
     <!-- some libraries should only be required for compiling/running tests -->
@@ -434,7 +432,7 @@
         <pathelement location="${main.byte-buddy.jar}"/>
         <pathelement location="${main.byte-buddy-agent.jar}"/>
         <pathelement location="${main.objenesis.jar}"/>
-        <pathelement location="${main.slf4j-simple.jar}"/>
+        <pathelement location="${main.log4j-core.jar}"/>
     </path>
 
     <path id="scratchpad.classpath">
@@ -519,7 +517,7 @@
         <path refid="ooxml.classpath"/>
         <path refid="ooxml.xmlsec.classpath"/>
         <path refid="test.jar.classpath"/>
-        <pathelement location="${main.slf4j-api.jar}"/>
+        <pathelement location="${main.log4j-api.jar}"/>
         <path path="${env.CLASSPATH}"/>
     </path>
 
@@ -658,7 +656,6 @@
         <condition property="jars.present">
             <or>
                 <and>
-                    <available file="${main.commons-logging.jar}"/>
                     <available file="${main.commons-codec.jar}"/>
                     <available file="${main.junit-api.jar}"/>
                     <available file="${main.junit-jengine.jar}"/>
@@ -678,8 +675,8 @@
                     <available file="${main.objenesis.jar}"/>
                     <available file="${main.ant.jar}"/>
                     <available file="${main.antlauncher.jar}"/>
-                    <available file="${main.slf4j-api.jar}"/>
-                    <available file="${main.slf4j-simple.jar}"/>
+                    <available file="${main.log4j-api.jar}"/>
+                    <available file="${main.log4j-core.jar}"/>
                     <available file="${asm.jar}"/>
                     <available file="${asm-commons.jar}"/>
                     <available file="${asm-tree.jar}"/>
@@ -704,7 +701,6 @@
     <target name="fetch-jars" depends="check-jars" unless="jars.present"
             description="Fetches needed JAR files from the Internet">
         <mkdir dir="${main.lib}"/>
-        <downloadfile src="${main.commons-logging.url}" dest="${main.commons-logging.jar}"/>
         <downloadfile src="${main.commons-codec.url}" dest="${main.commons-codec.jar}"/>
         <downloadfile src="${main.junit-api.url}" dest="${main.junit-api.jar}"/>
         <downloadfile src="${main.junit-jengine.url}" dest="${main.junit-jengine.jar}"/>
@@ -724,8 +720,8 @@
         <downloadfile src="${main.objenesis.url}" dest="${main.objenesis.jar}"/>
         <downloadfile src="${main.ant.url}" dest="${main.ant.jar}"/>
         <downloadfile src="${main.antlauncher.url}" dest="${main.antlauncher.jar}"/>
-        <downloadfile src="${main.slf4j-api.url}" dest="${main.slf4j-api.jar}"/>
-        <downloadfile src="${main.slf4j-simple.url}" dest="${main.slf4j-simple.jar}"/>
+        <downloadfile src="${main.log4j-api.url}" dest="${main.log4j-api.jar}"/>
+        <downloadfile src="${main.log4j-core.url}" dest="${main.log4j-core.jar}"/>
         <downloadfile src="${asm.url}" dest="${asm.jar}"/>
         <downloadfile src="${asm-commons.url}" dest="${asm-commons.jar}"/>
         <downloadfile src="${asm-tree.url}" dest="${asm-tree.jar}"/>
@@ -1285,10 +1281,6 @@
                         <jvmarg line="--add-modules org.junit.jupiter.params" unless:true="${isJava8}"/>
                         <jvmarg line="--add-modules org.apache.poi.@{module1}" if:set="use_module1"/>
                         <jvmarg line="--add-modules org.apache.poi.@{module2}" if:set="use_module2"/>
-
-                        <!-- mute some notorious talkative classes -->
-                        <jvmarg line="-Dorg.slf4j.simpleLogger.log.org.apache.poi.hdgf.chunks.Chunk=off"/>
-                        <jvmarg line="-Dorg.slf4j.simpleLogger.log.org.apache.poi=error"/>
                     </fork>
 
                     <listener classname="Junit5Progress" />
@@ -1683,7 +1675,7 @@
 
     <target name="test-integration" depends="compile-integration,-test-integration-check,jacocotask"
             unless="integration.test.notRequired">
-        <propertyreset name="org.apache.poi.util.POILogger" value="org.apache.poi.util.SLF4JLogger"/>
+        <propertyreset name="log4j.configurationFile" value="log4j2-console.xml"/>
         <delete dir="build" includes="test-integration.log*"/>
 
         <path id="test-integration.modules">
@@ -2210,9 +2202,9 @@
             <mappedresources cache="true">
                 <fileset dir="${main.lib}">
                     <include name="commons-codec-*.jar"/>
-                    <include name="commons-logging-*.jar"/>
                     <include name="commons-collections4-*.jar"/>
                     <include name="commons-math3-*.jar"/>
+                    <include name="log4j-api-*.jar"/>
                     <include name="SparseBitSet-*.jar"/>
                 </fileset>
                 <globmapper from="*" to="${zipdir}/lib/*"/>
@@ -2560,9 +2552,8 @@
             <auxClasspath path="${main.commons-collections4.jar}" />
             <auxClasspath path="${main.commons-math3.jar}" />
             <auxClasspath path="${main.commons-codec.jar}" />
-            <auxClasspath path="${main.commons-logging.jar}" />
-            <auxClasspath path="${main.slf4j-api.jar}" />
-            <auxClasspath path="${main.slf4j-simple.jar}" />
+            <auxClasspath path="${main.log4j-api.jar}" />
+            <auxClasspath path="${main.log4j-core.jar}" />
             <auxClasspath path="${main.junit-api.jar}" />
             <auxClasspath path="${main.junit-jengine.jar}" />
             <auxClasspath path="${main.junit-params.jar}" />
diff --git a/legal/LICENSE b/legal/LICENSE
index 3ce6efe..be6c2c6 100644
--- a/legal/LICENSE
+++ b/legal/LICENSE
@@ -285,29 +285,9 @@
     NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
     SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-SLF4J library (slf4j-api-*.jar)
+Log4j 2 library (log4j-api-*.jar)
 
-    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.
+    Apache License Version 2.0
 
 
 inbot-utils (https://github.com/Inbot/inbot-utils)
diff --git a/log4j2-console.xml b/log4j2-console.xml
new file mode 100644
index 0000000..745e420
--- /dev/null
+++ b/log4j2-console.xml
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements.  See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+-->
+<Configuration status="WARN" name="console">
+  <Appenders>
+    <Console name="Console" target="SYSTEM_OUT">
+      <PatternLayout pattern="%d [%t] %-5p %c - %m%n" />
+    </Console>
+  </Appenders>
+  <Loggers>
+    <Logger name="org.apache.poi.poifs.nio.FileBackedDataSource" level="ERROR" />
+    <Logger name="org.apache.poi.hdgf.chunks.Chunk" level="FATAL" />
+    <Logger name="org.apache.poi.hpsf.CodePageString" level="ERROR" />
+    <Logger name="org.apache.poi.hdgf.chunks.ChunkFactory" level="ERROR" />
+    <Logger name="org.apache.poi.hslf.model.textproperties.BitMaskTextProp" level="ERROR" />
+    <Logger name="org.apache.poi.hslf.usermodel.HSLFTextParagraph" level="ERROR" />
+    <Logger name="org.apache.poi.openxml4j.opc.ZipPackage" level="ERROR" />
+    <Logger name="org.apache.poi.POIDocument" level="WARN" />
+    <Logger name="org.apache.poi.openxml4j.opc.OPCPackage" level="ERROR" />
+    <Logger name="org.apache.poi.xssf.usermodel.XSSFWorkbook" level="ERROR" />
+    <Logger name="org.apache.poi.hslf.usermodel.HSLFGroupShape" level="WARN" />
+    <Logger name="org.apache.poi.hslf.record.Record" level="ERROR" />
+    <Root level="TRACE">
+      <AppenderRef ref="Console" />
+    </Root>
+  </Loggers>
+</Configuration>
diff --git a/log4j2-no-logging.xml b/log4j2-no-logging.xml
new file mode 100644
index 0000000..27ba74f
--- /dev/null
+++ b/log4j2-no-logging.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements.  See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+-->
+<Configuration status="OFF" name="no-logging">
+  <Loggers>
+    <Root level="OFF" />
+  </Loggers>
+</Configuration>
diff --git a/maven/poi.pom b/maven/poi.pom
index 8af45c0..743a3f3 100644
--- a/maven/poi.pom
+++ b/maven/poi.pom
@@ -57,14 +57,9 @@
 
     <dependencies>
         <dependency>
-            <groupId>org.slf4j</groupId>
-            <artifactId>slf4j-api</artifactId>
-            <version>1.7.30</version>
-        </dependency>
-        <dependency>
-            <groupId>org.slf4j</groupId>
-            <artifactId>jcl-over-slf4j</artifactId>
-            <version>1.7.30</version>
+            <groupId>org.apache.logging.log4j</groupId>
+            <artifactId>log4j-api</artifactId>
+            <version>2.14.0</version>
         </dependency>
         <dependency>
             <groupId>commons-codec</groupId>
diff --git a/osgi/README.md b/osgi/README.md
index 0ccbebf..a8c60bf 100644
--- a/osgi/README.md
+++ b/osgi/README.md
@@ -12,6 +12,7 @@
 - commons-compress
 - commons-collections4
 - commons-codec
+- Log4j 2 API
 
 ## Optional Dependencies
 
diff --git a/osgi/pom.xml b/osgi/pom.xml
index 4b97d09..97afc8b 100644
--- a/osgi/pom.xml
+++ b/osgi/pom.xml
@@ -74,6 +74,7 @@
                             !org.apache.commons.compress.*,
                             !com.zaxxer.sparsebits.*,
                             !com.graphbuilder.*,
+                            !org.apache.logging.log4j.*,
                             org.apache.batik.*;resolution:=optional,
                             org.apache.pdfbox.*;resolution:=optional,
                             org.apache.fontbox.*;resolution:=optional,
@@ -86,8 +87,6 @@
                             org.apache.xml.resolver.*;resolution:=optional,
                             org.apache.xml.security.*;resolution:=optional,
                             org.bouncycastle.*;resolution:=optional,
-                            org.apache.commons.logging.*;resolution:=optional,
-                            org.slf4j.*;resolution:=optional,
                             !com.github.luben.zstd.*,
                             !org.tukaani.xz.*,
                             !org.brotli.dec.*,
@@ -104,7 +103,8 @@
                             commons-math3,
                             commons-compress,
                             commons-collections4,
-                            commons-codec
+                            commons-codec,
+                            log4j-api
                         </Embed-Dependency>
                         <Embed-Directory>lib</Embed-Directory>
                         <Embed-Transitive>true</Embed-Transitive>
@@ -228,9 +228,9 @@
             <scope>test</scope>
         </dependency>
         <dependency>
-            <groupId>org.slf4j</groupId>
-            <artifactId>slf4j-simple</artifactId>
-            <version>1.7.30</version>
+            <groupId>org.apache.logging.log4j</groupId>
+            <artifactId>log4j-core</artifactId>
+            <version>2.14.0</version>
             <scope>test</scope>
         </dependency>
     </dependencies>
diff --git a/sonar/main/pom.xml b/sonar/main/pom.xml
index b20321c..97ab8f3 100644
--- a/sonar/main/pom.xml
+++ b/sonar/main/pom.xml
@@ -101,14 +101,9 @@
 
     <dependencies>
         <dependency>
-            <groupId>org.slf4j</groupId>
-            <artifactId>slf4j-api</artifactId>
-            <version>1.7.30</version>
-        </dependency>
-        <dependency>
-            <groupId>org.slf4j</groupId>
-            <artifactId>jcl-over-slf4j</artifactId>
-            <version>1.7.30</version>
+            <groupId>org.apache.logging.log4j</groupId>
+            <artifactId>log4j-api</artifactId>
+            <version>2.14.0</version>
         </dependency>
         <dependency>
             <groupId>commons-codec</groupId>
diff --git a/sonar/pom.xml b/sonar/pom.xml
index fc16a89..68c89d6 100644
--- a/sonar/pom.xml
+++ b/sonar/pom.xml
@@ -115,7 +115,7 @@
                     <systemPropertyVariables>
                         <POI.testdata.path>../../test-data</POI.testdata.path>
                         <java.awt.headless>true</java.awt.headless>
-                        <org.apache.poi.util.POILogger>org.apache.poi.util.NullLogger</org.apache.poi.util.POILogger>
+                        <log4j.configurationFile>log4j2-no-logging.xml</log4j.configurationFile>
                     </systemPropertyVariables>
                     <!-- use to following to analyze OOM issues:	-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/tmp -->
                     <argLine>@{argLine} -Duser.language=en -Duser.country=US -Xmx1024m -Djava.io.tmpdir=${basedir}/target/tmp -XX:-OmitStackTraceInFastThrow</argLine>
diff --git a/src/examples/src/org/apache/poi/examples/hssf/usermodel/Outlines.java b/src/examples/src/org/apache/poi/examples/hssf/usermodel/Outlines.java
index b512144..42f1b16 100644
--- a/src/examples/src/org/apache/poi/examples/hssf/usermodel/Outlines.java
+++ b/src/examples/src/org/apache/poi/examples/hssf/usermodel/Outlines.java
@@ -22,12 +22,12 @@
 import java.io.IOException;
 import java.lang.reflect.InvocationTargetException;
 
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.apache.poi.hssf.usermodel.HSSFCell;
 import org.apache.poi.hssf.usermodel.HSSFRow;
 import org.apache.poi.hssf.usermodel.HSSFSheet;
 import org.apache.poi.hssf.usermodel.HSSFWorkbook;
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
 
 /**
  * Creates outlines.
@@ -35,13 +35,13 @@
 public class Outlines implements Closeable {
     public static void main(String[] args)
     throws IOException, IllegalAccessException, InvocationTargetException, NoSuchMethodException {
-        POILogger LOGGER = POILogFactory.getLogger(Outlines.class);
+        Logger LOGGER = LogManager.getLogger(Outlines.class);
         for (int i=1; i<=13; i++) {
             try (Outlines o = new Outlines()) {
                 String log = (String) Outlines.class.getDeclaredMethod("test" + i).invoke(o);
                 String filename = "outline" + i + ".xls";
                 o.writeOut(filename);
-                LOGGER.log(POILogger.INFO, filename, " written. ", log);
+                LOGGER.atInfo().log("{} written. {}", filename, log);
             }
         }
     }
diff --git a/src/integrationtest/commons-logging.properties b/src/integrationtest/commons-logging.properties
deleted file mode 100644
index 45db0a7..0000000
--- a/src/integrationtest/commons-logging.properties
+++ /dev/null
@@ -1,16 +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.configuration=log4j.properties
\ No newline at end of file
diff --git a/src/integrationtest/log4j.properties b/src/integrationtest/log4j.properties
deleted file mode 100644
index 85a87f5..0000000
--- a/src/integrationtest/log4j.properties
+++ /dev/null
@@ -1,39 +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, R

-

-log4j.appender.R=org.apache.log4j.RollingFileAppender

-log4j.appender.R.File=build/test-integration.log

-

-log4j.appender.R.MaxFileSize=1000KB

-# Keep one backup file

-log4j.appender.R.MaxBackupIndex=5

-

-log4j.appender.R.layout=org.apache.log4j.PatternLayout

-log4j.appender.R.layout.ConversionPattern=%d [%t] %-5p %c - %m%n

-

-log4j.logger.org.apache.poi.poifs.nio.FileBackedDataSource=ERROR

-log4j.logger.org.apache.poi.hdgf.chunks.Chunk=FATAL

-log4j.logger.org.apache.poi.hpsf.CodePageString=ERROR

-log4j.logger.org.apache.poi.hdgf.chunks.ChunkFactory=ERROR

-log4j.logger.org.apache.poi.hslf.model.textproperties.BitMaskTextProp=ERROR

-log4j.logger.org.apache.poi.hslf.usermodel.HSLFTextParagraph=ERROR

-log4j.logger.org.apache.poi.openxml4j.opc.ZipPackage=ERROR

-log4j.logger.org.apache.poi.POIDocument=WARN

-log4j.logger.org.apache.poi.openxml4j.opc.OPCPackage=ERROR

-log4j.logger.org.apache.poi.xssf.usermodel.XSSFWorkbook=ERROR

-log4j.logger.org.apache.poi.hslf.usermodel.HSLFGroupShape=WARN

-log4j.logger.org.apache.poi.hslf.record.Record=ERROR
\ No newline at end of file
diff --git a/src/integrationtest/org/apache/poi/stress/HSLFFileHandler.java b/src/integrationtest/org/apache/poi/stress/HSLFFileHandler.java
index 3ea92dd..d1f3730 100644
--- a/src/integrationtest/org/apache/poi/stress/HSLFFileHandler.java
+++ b/src/integrationtest/org/apache/poi/stress/HSLFFileHandler.java
@@ -23,13 +23,16 @@
 import java.io.FileInputStream;
 import java.io.InputStream;
 
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.apache.poi.hslf.usermodel.HSLFSlideShow;
 import org.apache.poi.hslf.usermodel.HSLFSlideShowImpl;
-import org.apache.poi.util.POILogger;
-import org.apache.poi.util.SystemOutLogger;
 import org.junit.jupiter.api.Test;
 
 class HSLFFileHandler extends SlideShowHandler {
+
+    private static final Logger LOGGER = LogManager.getLogger(HSLFFileHandler.class);
+
     @Override
     public void handleFile(InputStream stream, String path) throws Exception {
         HSLFSlideShowImpl slide = new HSLFSlideShowImpl(stream);
@@ -64,12 +67,11 @@
 
         System.out.println("Testing " + files.length + " files");
 
-        POILogger logger = new SystemOutLogger();
         for(File file : files) {
             try {
                 testOneFile(file);
             } catch (Throwable e) {
-                logger.log(POILogger.WARN, "Failed to handle file ", file, e);
+                LOGGER.atWarn().withThrowable(e).log("Failed to handle file {}", file);
             }
         }
     }
@@ -77,7 +79,6 @@
     private void testOneFile(File file) throws Exception {
         System.out.println(file);
 
-        //System.setProperty("org.apache.poi.util.POILogger", "org.apache.poi.util.SystemOutLogger");
         try (InputStream stream = new FileInputStream(file)) {
             handleFile(stream, file.getPath());
         }
@@ -86,7 +87,7 @@
     }
 
     public static void main(String[] args) throws Exception {
-        System.setProperty("org.apache.poi.util.POILogger", "org.apache.poi.util.SystemOutLogger");
+        System.setProperty("log4j.configurationFile", "log4j2-console.xml");
         try (InputStream stream = new FileInputStream(args[0])) {
             new HSLFFileHandler().handleFile(stream, args[0]);
         }
diff --git a/src/java/org/apache/poi/POIDocument.java b/src/java/org/apache/poi/POIDocument.java
index 9752169..2a2c1ac 100644
--- a/src/java/org/apache/poi/POIDocument.java
+++ b/src/java/org/apache/poi/POIDocument.java
@@ -17,18 +17,23 @@
 
 package org.apache.poi;
 
+import static org.apache.logging.log4j.util.Unbox.box;
 import static org.apache.poi.hpsf.PropertySetFactory.newDocumentSummaryInformation;
 
+import java.io.BufferedOutputStream;
 import java.io.ByteArrayInputStream;
 import java.io.ByteArrayOutputStream;
 import java.io.Closeable;
 import java.io.File;
+import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
 import java.security.GeneralSecurityException;
 import java.util.List;
 
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.apache.poi.hpsf.DocumentSummaryInformation;
 import org.apache.poi.hpsf.PropertySet;
 import org.apache.poi.hpsf.PropertySetFactory;
@@ -43,8 +48,6 @@
 import org.apache.poi.poifs.filesystem.POIFSFileSystem;
 import org.apache.poi.util.IOUtils;
 import org.apache.poi.util.Internal;
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
 
 /**
  * This holds the common functionality for all POI
@@ -60,7 +63,7 @@
     private DirectoryNode directory;
 
     /** For our own logging use */
-    private static final POILogger LOG = POILogFactory.getLogger(POIDocument.class);
+    private static final Logger LOG = LogManager.getLogger(POIDocument.class);
 
     /* Have the property streams been read yet? (Only done on-demand) */
     private boolean initialized;
@@ -162,12 +165,12 @@
             if (clazz.isInstance(ps)) {
                 return (T)ps;
             } else if (ps != null) {
-                LOG.log(POILogger.WARN, localName+" property set came back with wrong class - "+ps.getClass().getName());
+                LOG.atWarn().log("{} property set came back with wrong class - {}", localName, ps.getClass().getName());
             } else {
-                LOG.log(POILogger.WARN, localName+" property set came back as null");
+                LOG.atWarn().log("{} property set came back as null {}", localName, box(5));
             }
         } catch (IOException e) {
-            LOG.log(POILogger.ERROR, "can't retrieve property set", e);
+            LOG.atError().withThrowable(e).log("can't retrieve property set");
         }
         return null;
     }
@@ -333,9 +336,9 @@
             // Create or Update the Property Set stream in the POIFS
             outFS.createOrUpdateDocument(bIn, name);
 
-            LOG.log(POILogger.INFO, "Wrote property set ", name, " of size ", data.length);
+            LOG.atInfo().log("Wrote property set {} of size {}", name, box(data.length));
         } catch(WritingNotSupportedException ignored) {
-            LOG.log( POILogger.ERROR, "Couldn't write property set with name ", name, " as not supported by HPSF yet");
+            LOG.atError().log("Couldn't write property set with name {} as not supported by HPSF yet", name);
         }
     }
 
@@ -397,9 +400,9 @@
      *  {@link #write()} or to a different File. Overwriting the currently
      *  open file via an OutputStream isn't possible.
      *
-     * If {@code stream} is a {@link java.io.FileOutputStream} on a networked drive
+     * If {@code stream} is a {@link FileOutputStream} on a networked drive
      * or has a high cost/latency associated with each written byte,
-     * consider wrapping the OutputStream in a {@link java.io.BufferedOutputStream}
+     * consider wrapping the OutputStream in a {@link BufferedOutputStream}
      * to improve write performance, or use {@link #write()} / {@link #write(File)}
      * if possible.
      *
diff --git a/src/java/org/apache/poi/common/usermodel/fonts/FontCharset.java b/src/java/org/apache/poi/common/usermodel/fonts/FontCharset.java
index 28df6ca..0447657 100644
--- a/src/java/org/apache/poi/common/usermodel/fonts/FontCharset.java
+++ b/src/java/org/apache/poi/common/usermodel/fonts/FontCharset.java
@@ -20,8 +20,8 @@
 import java.nio.charset.Charset;
 import java.nio.charset.UnsupportedCharsetException;
 
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 
 /**
  * Charset represents the basic set of characters associated with a font (that it can display), and
@@ -99,8 +99,8 @@
                 charset = Charset.forName(javaCharsetName);
                 return;
             } catch (UnsupportedCharsetException e) {
-                POILogger logger = POILogFactory.getLogger(FontCharset.class);
-                logger.log(POILogger.WARN, "Unsupported charset: "+javaCharsetName);
+                Logger logger = LogManager.getLogger(FontCharset.class);
+                logger.atWarn().log("Unsupported charset: {}", javaCharsetName);
             }
         }
         charset = null;
diff --git a/src/java/org/apache/poi/ddf/EscherContainerRecord.java b/src/java/org/apache/poi/ddf/EscherContainerRecord.java
index 0f19293..474b24a 100644
--- a/src/java/org/apache/poi/ddf/EscherContainerRecord.java
+++ b/src/java/org/apache/poi/ddf/EscherContainerRecord.java
@@ -25,11 +25,13 @@
 import java.util.Map;
 import java.util.function.Supplier;
 
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.apache.poi.util.GenericRecordUtil;
 import org.apache.poi.util.HexDump;
 import org.apache.poi.util.LittleEndian;
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
+
+import static org.apache.logging.log4j.util.Unbox.box;
 
 /**
  * Escher container records store other escher records as children.
@@ -45,7 +47,7 @@
     public static final short SP_CONTAINER     = EscherRecordTypes.SP_CONTAINER.typeID;
     public static final short SOLVER_CONTAINER = EscherRecordTypes.SOLVER_CONTAINER.typeID;
 
-    private static final POILogger log = POILogFactory.getLogger(EscherContainerRecord.class);
+    private static final Logger LOGGER = LogManager.getLogger(EscherContainerRecord.class);
 
     /**
      * in case if document contains any charts we have such document structure:
@@ -95,9 +97,7 @@
             addChildRecord(child);
             if (offset >= data.length && bytesRemaining > 0) {
                 _remainingLength = bytesRemaining;
-                if (log.check(POILogger.WARN)) {
-                    log.log(POILogger.WARN, "Not enough Escher data: " + bytesRemaining + " bytes remaining but no space left");
-                }
+                LOGGER.atWarn().log("Not enough Escher data: {} bytes remaining but no space left", box(bytesRemaining));
             }
         }
         return bytesWritten;
diff --git a/src/java/org/apache/poi/ddf/EscherMetafileBlip.java b/src/java/org/apache/poi/ddf/EscherMetafileBlip.java
index 19b4e20..6713b5f 100644
--- a/src/java/org/apache/poi/ddf/EscherMetafileBlip.java
+++ b/src/java/org/apache/poi/ddf/EscherMetafileBlip.java
@@ -29,14 +29,16 @@
 import java.util.zip.DeflaterOutputStream;
 import java.util.zip.InflaterInputStream;
 
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.apache.poi.hssf.usermodel.HSSFPictureData;
 import org.apache.poi.util.IOUtils;
 import org.apache.poi.util.LittleEndian;
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
+
+import static org.apache.logging.log4j.util.Unbox.box;
 
 public final class EscherMetafileBlip extends EscherBlipRecord {
-    private static final POILogger log = POILogFactory.getLogger(EscherMetafileBlip.class);
+    private static final Logger LOGGER = LogManager.getLogger(EscherMetafileBlip.class);
     //arbitrarily selected; may need to increase
     private static final int MAX_RECORD_LENGTH = 100_000_000;
 
@@ -175,7 +177,7 @@
             }
             return out.toByteArray();
         } catch (IOException e) {
-            log.log(POILogger.WARN, "Possibly corrupt compression or non-compressed data", e);
+            LOGGER.atWarn().withThrowable(e).log("Possibly corrupt compression or non-compressed data");
             return data;
         }
     }
@@ -375,9 +377,7 @@
             case BLIP_WMF:  return HSSFPictureData.MSOBI_WMF;
             case BLIP_PICT: return HSSFPictureData.MSOBI_PICT;
         }
-        if (log.check(POILogger.WARN)) {
-            log.log(POILogger.WARN, "Unknown metafile: " + getRecordId());
-        }
+        LOGGER.atWarn().log("Unknown metafile: {}", box(getRecordId()));
         return 0;
     }
 
diff --git a/src/java/org/apache/poi/extractor/ExtractorFactory.java b/src/java/org/apache/poi/extractor/ExtractorFactory.java
index c310715..a8d2f2d 100644
--- a/src/java/org/apache/poi/extractor/ExtractorFactory.java
+++ b/src/java/org/apache/poi/extractor/ExtractorFactory.java
@@ -27,6 +27,8 @@
 import java.util.ServiceLoader;
 import java.util.stream.StreamSupport;
 
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.apache.poi.EmptyFileException;
 import org.apache.poi.hssf.extractor.ExcelExtractor;
 import org.apache.poi.poifs.crypt.Decryptor;
@@ -36,8 +38,6 @@
 import org.apache.poi.poifs.filesystem.FileMagic;
 import org.apache.poi.poifs.filesystem.POIFSFileSystem;
 import org.apache.poi.util.IOUtils;
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
 
 /**
  * Figures out the correct POIOLE2TextExtractor for your supplied
@@ -60,7 +60,7 @@
      */
     public static final String OOXML_PACKAGE = "Package";
 
-    private static final POILogger LOGGER = POILogFactory.getLogger(ExtractorFactory.class);
+    private static final Logger LOGGER = LogManager.getLogger(ExtractorFactory.class);
 
     /** Should this thread prefer event based over usermodel based extractors? */
     private static final ThreadLocal<Boolean> threadPreferEventExtractors = ThreadLocal.withInitial(() -> Boolean.FALSE);
@@ -293,7 +293,7 @@
                 textExtractors.add(createExtractor(stream));
             } catch (IOException e) {
                 // Ignore, just means it didn't contain a format we support as yet
-                LOGGER.log(POILogger.INFO, "Format not supported yet", e.getLocalizedMessage());
+                LOGGER.atInfo().log("Format not supported yet ({})", e.getLocalizedMessage());
             }
         }
         return textExtractors.toArray(new POITextExtractor[0]);
diff --git a/src/java/org/apache/poi/hpsf/ClipboardData.java b/src/java/org/apache/poi/hpsf/ClipboardData.java
index a5b1815..d92269a 100644
--- a/src/java/org/apache/poi/hpsf/ClipboardData.java
+++ b/src/java/org/apache/poi/hpsf/ClipboardData.java
@@ -16,20 +16,22 @@
 ==================================================================== */
 package org.apache.poi.hpsf;
 
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.apache.poi.util.IOUtils;
 import org.apache.poi.util.Internal;
 import org.apache.poi.util.LittleEndian;
 import org.apache.poi.util.LittleEndianByteArrayInputStream;
 import org.apache.poi.util.LittleEndianConsts;
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
+
+import static org.apache.logging.log4j.util.Unbox.box;
 
 @Internal
 public class ClipboardData {
     //arbitrarily selected; may need to increase
     private static final int MAX_RECORD_LENGTH = 100_000_000;
 
-    private static final POILogger LOG = POILogFactory.getLogger( ClipboardData.class );
+    private static final Logger LOG = LogManager.getLogger(ClipboardData.class);
 
     private int _format;
     private byte[] _value;
@@ -39,10 +41,8 @@
         long size = lei.readInt();
 
         if ( size < 4 ) {
-            String msg =
-                "ClipboardData at offset "+offset+" size less than 4 bytes "+
-                "(doesn't even have format field!). Setting to format == 0 and hope for the best";
-            LOG.log( POILogger.WARN, msg);
+            LOG.atWarn().log("ClipboardData at offset {} size less than 4 bytes (doesn't even have format " +
+                    "field!). Setting to format == 0 and hope for the best", box(offset));
             _format = 0;
             _value = new byte[0];
             return;
diff --git a/src/java/org/apache/poi/hpsf/CodePageString.java b/src/java/org/apache/poi/hpsf/CodePageString.java
index 7cd6b5a..4ba9b0d 100644
--- a/src/java/org/apache/poi/hpsf/CodePageString.java
+++ b/src/java/org/apache/poi/hpsf/CodePageString.java
@@ -20,21 +20,23 @@
 import java.io.OutputStream;
 import java.io.UnsupportedEncodingException;
 
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.apache.poi.util.CodePageUtil;
 import org.apache.poi.util.IOUtils;
 import org.apache.poi.util.Internal;
 import org.apache.poi.util.LittleEndian;
 import org.apache.poi.util.LittleEndianByteArrayInputStream;
 import org.apache.poi.util.LittleEndianConsts;
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
+
+import static org.apache.logging.log4j.util.Unbox.box;
 
 @Internal
 public class CodePageString {
     //arbitrarily selected; may need to increase
     private static final int MAX_RECORD_LENGTH = 100_000;
 
-    private static final POILogger LOG = POILogFactory.getLogger( CodePageString.class );
+    private static final Logger LOG = LogManager.getLogger(CodePageString.class);
 
     private byte[] _value;
 
@@ -61,8 +63,7 @@
             // TODO Some files, such as TestVisioWithCodepage.vsd, are currently
             // triggering this for values that don't look like codepages
             // See Bug #52258 for details
-            String msg = "CodePageString started at offset #" + offset + " is not NULL-terminated";
-            LOG.log(POILogger.WARN, msg);
+            LOG.atWarn().log("CodePageString started at offset #{} is not NULL-terminated", box(offset));
         }
 
         TypedPropertyValue.skipPadding(lei);
@@ -75,17 +76,13 @@
 
         final int terminator = result.indexOf( '\0' );
         if ( terminator == -1 ) {
-            String msg =
-                "String terminator (\\0) for CodePageString property value not found. " +
-                "Continue without trimming and hope for the best.";
-            LOG.log(POILogger.WARN, msg);
+            LOG.atWarn().log("String terminator (\\0) for CodePageString property value not found. " +
+            "Continue without trimming and hope for the best.");
             return result;
         }
         if ( terminator != result.length() - 1 ) {
-            String msg =
-                "String terminator (\\0) for CodePageString property value occured before the end of string. "+
-                "Trimming and hope for the best.";
-            LOG.log(POILogger.WARN, msg );
+            LOG.atWarn().log("String terminator (\\0) for CodePageString property value occurred before the end of " +
+                    "string. Trimming and hope for the best.");
         }
         return result.substring( 0, terminator );
     }
diff --git a/src/java/org/apache/poi/hpsf/CustomProperties.java b/src/java/org/apache/poi/hpsf/CustomProperties.java
index 6e90183..e260e30 100644
--- a/src/java/org/apache/poi/hpsf/CustomProperties.java
+++ b/src/java/org/apache/poi/hpsf/CustomProperties.java
@@ -31,10 +31,12 @@
 import java.util.Set;
 
 import org.apache.commons.collections4.bidimap.TreeBidiMap;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.apache.poi.hpsf.wellknown.PropertyIDMap;
 import org.apache.poi.util.CodePageUtil;
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
+
+import static org.apache.logging.log4j.util.Unbox.box;
 
 /**
  * Maintains the instances of {@link CustomProperty} that belong to a
@@ -65,8 +67,8 @@
  * HashMap&lt;String,Object&gt; mapping between Names and Custom Property Values.
  */
 public class CustomProperties implements Map<String,Object> {
-    private static final POILogger LOG = POILogFactory.getLogger(CustomProperties.class);
-    
+    private static final Logger LOG = LogManager.getLogger(CustomProperties.class);
+
     /**
      * The custom properties
      */
@@ -207,7 +209,7 @@
 
     @Override
     public void putAll(Map<? extends String, ?> m) {
-        for (Map.Entry<? extends String, ?> me : m.entrySet()) {
+        for (Entry<? extends String, ?> me : m.entrySet()) {
             put(me.getKey(), me.getValue());
         }
     }
@@ -393,12 +395,12 @@
         try {
             cps = CodePageUtil.codepageToEncoding(cp, false);
         } catch (UnsupportedEncodingException e) {
-            LOG.log(POILogger.ERROR, "Codepage '", cp, "' can't be found.");
+            LOG.atError().log("Codepage '{}' can't be found.", box(cp));
         }
         if (!cps.isEmpty() && Charset.forName(cps).newEncoder().canEncode(value)) {
             return;
         }
-        LOG.log(POILogger.DEBUG, "Charset '"+cps+"' can't encode '"+value+"' - switching to unicode.");
+        LOG.atDebug().log("Charset '{}' can't encode '{}' - switching to unicode.", cps, value);
         setCodepage(CodePageUtil.CP_UNICODE);
     }
 }
diff --git a/src/java/org/apache/poi/hpsf/Property.java b/src/java/org/apache/poi/hpsf/Property.java
index 8e45771..0e3e2cd 100644
--- a/src/java/org/apache/poi/hpsf/Property.java
+++ b/src/java/org/apache/poi/hpsf/Property.java
@@ -24,10 +24,13 @@
 import java.nio.charset.Charset;
 import java.text.DateFormat;
 import java.text.SimpleDateFormat;
+import java.util.Date;
 import java.util.Locale;
 import java.util.Objects;
 import java.util.concurrent.TimeUnit;
 
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.apache.poi.hpsf.wellknown.PropertyIDMap;
 import org.apache.poi.util.CodePageUtil;
 import org.apache.poi.util.HexDump;
@@ -35,8 +38,8 @@
 import org.apache.poi.util.LittleEndianByteArrayInputStream;
 import org.apache.poi.util.LittleEndianConsts;
 import org.apache.poi.util.LocaleUtil;
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
+
+import static org.apache.logging.log4j.util.Unbox.box;
 
 /**
  * A property in a {@link Section} of a {@link PropertySet}.<p>
@@ -70,7 +73,7 @@
      */
     public static final int DEFAULT_CODEPAGE = CodePageUtil.CP_WINDOWS_1252;
 
-    private static final POILogger LOG = POILogFactory.getLogger(Property.class);
+    private static final Logger LOG = LogManager.getLogger(Property.class);
 
     /** The property's ID. */
     private long id;
@@ -293,7 +296,7 @@
      * section's dictionary. Another special case are strings: Two properties
      * may have the different types Variant.VT_LPSTR and Variant.VT_LPWSTR;
      *
-     * @see Object#equals(java.lang.Object)
+     * @see Object#equals(Object)
      */
     @Override
     public boolean equals(final Object o) {
@@ -412,7 +415,7 @@
             try {
                 write(bos, codepage);
             } catch (Exception e) {
-                LOG.log(POILogger.WARN, "can't serialize string", e);
+                LOG.atWarn().withThrowable(e).log("can't serialize string");
             }
 
             // skip length field
@@ -427,8 +430,8 @@
                 String hex = HexDump.dump(bytes, 0L, 0);
                 b.append(hex);
             }
-        } else if (value instanceof java.util.Date) {
-            java.util.Date d = (java.util.Date)value;
+        } else if (value instanceof Date) {
+            Date d = (Date)value;
             long filetime = Filetime.dateToFileTime(d);
             if (Filetime.isUndefined(d)) {
                 b.append("<undefined>");
@@ -484,7 +487,7 @@
                     return LocaleUtil.getLocaleFromLCID(((Number)value).intValue());
             }
         } catch (Exception e) {
-            LOG.log(POILogger.WARN, "Can't decode id "+getID());
+            LOG.atWarn().log("Can't decode id {}", box(getID()));
         }
         return null;
     }
diff --git a/src/java/org/apache/poi/hpsf/Section.java b/src/java/org/apache/poi/hpsf/Section.java
index 89802a0..c404e49 100644
--- a/src/java/org/apache/poi/hpsf/Section.java
+++ b/src/java/org/apache/poi/hpsf/Section.java
@@ -31,6 +31,8 @@
 import java.util.TreeMap;
 
 import org.apache.commons.collections4.bidimap.TreeBidiMap;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.apache.poi.hpsf.wellknown.PropertyIDMap;
 import org.apache.poi.util.CodePageUtil;
 import org.apache.poi.util.IOUtils;
@@ -38,8 +40,6 @@
 import org.apache.poi.util.LittleEndianByteArrayInputStream;
 import org.apache.poi.util.LittleEndianConsts;
 import org.apache.poi.util.LittleEndianOutputStream;
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
 
 /**
  * Represents a section in a {@link PropertySet}.
@@ -48,7 +48,7 @@
     //arbitrarily selected; may need to increase
     private static final int MAX_RECORD_LENGTH = 100_000;
 
-    private static final POILogger LOG = POILogFactory.getLogger(Section.class);
+    private static final Logger LOG = LogManager.getLogger(Section.class);
 
     /**
      * Maps property IDs to section-private PID strings. These
@@ -235,7 +235,7 @@
                         id = Math.max(PropertyIDMap.PID_MAX, offset2Id.inverseBidiMap().lastKey())+1;
                         setProperty(new Property(id, leis, pLen, codepage));
                     } catch (RuntimeException e) {
-                        LOG.log(POILogger.INFO, "Dictionary fallback failed - ignoring property");
+                        LOG.atInfo().log("Dictionary fallback failed - ignoring property");
                     }
                 }
             } else {
@@ -730,10 +730,8 @@
          * (property 0) the codepage property (property 1) must be set, too. */
         int codepage = getCodepage();
         if (codepage == -1) {
-            String msg =
-                "The codepage property is not set although a dictionary is present. "+
-                "Defaulting to ISO-8859-1.";
-            LOG.log(POILogger.WARN, msg);
+            LOG.atWarn().log("The codepage property is not set although a dictionary is present. " +
+                    "Defaulting to ISO-8859-1.");
             codepage = Property.DEFAULT_CODEPAGE;
         }
 
@@ -826,7 +824,7 @@
             int cp = (codepage == -1) ? Property.DEFAULT_CODEPAGE : codepage;
             int nrBytes = Math.toIntExact(((sLength-1) * (cp == CodePageUtil.CP_UNICODE ? 2 : 1)));
             if (nrBytes > 0xFFFFFF) {
-                LOG.log(POILogger.WARN, errMsg);
+                LOG.atWarn().log(errMsg);
                 isCorrupted = true;
                 break;
             }
@@ -844,7 +842,7 @@
 
                 dic.put(id, str);
             } catch (RuntimeException|IOException ex) {
-                LOG.log(POILogger.WARN, errMsg, ex);
+                LOG.atWarn().withThrowable(ex).log(errMsg);
                 isCorrupted = true;
                 break;
             }
@@ -894,8 +892,8 @@
 
     /**
      * Sets the section's dictionary. All keys in the dictionary must be
-     * {@link java.lang.Long} instances, all values must be
-     * {@link java.lang.String}s. This method overwrites the properties with IDs
+     * {@link Long} instances, all values must be
+     * {@link String}s. This method overwrites the properties with IDs
      * 0 and 1 since they are reserved for the dictionary and the dictionary's
      * codepage. Setting these properties explicitly might have surprising
      * effects. An application should never do this but always use this
diff --git a/src/java/org/apache/poi/hpsf/TypedPropertyValue.java b/src/java/org/apache/poi/hpsf/TypedPropertyValue.java
index 0cba4a6..1b4f5c6 100644
--- a/src/java/org/apache/poi/hpsf/TypedPropertyValue.java
+++ b/src/java/org/apache/poi/hpsf/TypedPropertyValue.java
@@ -20,15 +20,17 @@
 
 import java.math.BigInteger;
 
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.apache.poi.util.Internal;
 import org.apache.poi.util.LittleEndianByteArrayInputStream;
 import org.apache.poi.util.LittleEndianConsts;
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
+
+import static org.apache.logging.log4j.util.Unbox.box;
 
 @Internal
 public class TypedPropertyValue {
-    private static final POILogger LOG = POILogFactory.getLogger( TypedPropertyValue.class );
+    private static final Logger LOG = LogManager.getLogger(TypedPropertyValue.class);
 
     private int _type;
     private Object _value;
@@ -46,8 +48,7 @@
         _type = lei.readShort();
         short padding = lei.readShort();
         if ( padding != 0 ) {
-            LOG.log( POILogger.WARN, "TypedPropertyValue padding at offset "
-                    + lei.getReadIndex() + " MUST be 0, but it's value is " + padding );
+            LOG.atWarn().log("TypedPropertyValue padding at offset {} MUST be 0, but it's value is {}", box(lei.getReadIndex()),box(padding));
         }
         readValue( lei );
     }
diff --git a/src/java/org/apache/poi/hpsf/UnicodeString.java b/src/java/org/apache/poi/hpsf/UnicodeString.java
index f6be7d3..866a2b2 100644
--- a/src/java/org/apache/poi/hpsf/UnicodeString.java
+++ b/src/java/org/apache/poi/hpsf/UnicodeString.java
@@ -20,19 +20,19 @@
 import java.io.OutputStream;
 import java.io.UnsupportedEncodingException;
 
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.apache.poi.util.CodePageUtil;
 import org.apache.poi.util.IOUtils;
 import org.apache.poi.util.Internal;
 import org.apache.poi.util.LittleEndian;
 import org.apache.poi.util.LittleEndianByteArrayInputStream;
 import org.apache.poi.util.LittleEndianConsts;
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
 import org.apache.poi.util.StringUtil;
 
 @Internal
 public class UnicodeString {
-    private static final POILogger LOG = POILogFactory.getLogger( UnicodeString.class );
+    private static final Logger LOG = LogManager.getLogger(UnicodeString.class);
     //arbitrarily selected; may need to increase
     private static final int MAX_RECORD_LENGTH = 100_000;
 
@@ -77,18 +77,14 @@
 
         final int terminator = result.indexOf( '\0' );
         if ( terminator == -1 ) {
-            String msg =
-                "String terminator (\\0) for UnicodeString property value not found. " +
-                "Continue without trimming and hope for the best.";
-            LOG.log(POILogger.WARN, msg);
+            LOG.atWarn().log("String terminator (\\0) for UnicodeString property value not found. " +
+                    "Continue without trimming and hope for the best.");
             return result;
         }
         
         if ( terminator != result.length() - 1 ) {
-            String msg =
-                "String terminator (\\0) for UnicodeString property value occured before the end of string. " +
-                "Trimming and hope for the best.";
-            LOG.log(POILogger.WARN, msg);
+            LOG.atWarn().log("String terminator (\\0) for UnicodeString property value occured before the end of " +
+                    "string. Trimming and hope for the best.");
         }
         return result.substring( 0, terminator );
     }
diff --git a/src/java/org/apache/poi/hpsf/VariantBool.java b/src/java/org/apache/poi/hpsf/VariantBool.java
index dc86594..0f59164 100644
--- a/src/java/org/apache/poi/hpsf/VariantBool.java
+++ b/src/java/org/apache/poi/hpsf/VariantBool.java
@@ -16,14 +16,16 @@
 ==================================================================== */
 package org.apache.poi.hpsf;
 
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.apache.poi.util.Internal;
 import org.apache.poi.util.LittleEndianByteArrayInputStream;
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
+
+import static org.apache.logging.log4j.util.Unbox.box;
 
 @Internal
 public class VariantBool {
-    private static final POILogger LOG = POILogFactory.getLogger( VariantBool.class );
+    private static final Logger LOG = LogManager.getLogger(VariantBool.class);
 
     static final int SIZE = 2;
 
@@ -39,7 +41,7 @@
                 _value = true;
                 break;
             default:
-                LOG.log( POILogger.WARN, "VARIANT_BOOL value '"+value+"' is incorrect" );
+                LOG.atWarn().log("VARIANT_BOOL value '{}' is incorrect", box(value));
                 _value = true;
                 break;
         }
diff --git a/src/java/org/apache/poi/hpsf/VariantSupport.java b/src/java/org/apache/poi/hpsf/VariantSupport.java
index 4fd4a7e..5d49c8a 100644
--- a/src/java/org/apache/poi/hpsf/VariantSupport.java
+++ b/src/java/org/apache/poi/hpsf/VariantSupport.java
@@ -25,12 +25,12 @@
 import java.util.LinkedList;
 import java.util.List;
 
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.apache.poi.util.IOUtils;
 import org.apache.poi.util.LittleEndian;
 import org.apache.poi.util.LittleEndianByteArrayInputStream;
 import org.apache.poi.util.LittleEndianConsts;
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
 
 /**
  * Supports reading and writing of variant data.<p>
@@ -58,7 +58,7 @@
             Variant.VT_CF, Variant.VT_BOOL };
 
 
-    private static final POILogger LOG = POILogFactory.getLogger(VariantSupport.class);
+    private static final Logger LOG = LogManager.getLogger(VariantSupport.class);
     //arbitrarily selected; may need to increase
     private static final int MAX_RECORD_LENGTH = 100_000;
 
@@ -114,7 +114,7 @@
             Long vt = Long.valueOf(ex.getVariantType());
             if (!unsupportedMessage.contains(vt))
             {
-            	LOG.log( POILogger.ERROR, ex.getMessage());
+            	LOG.atError().withThrowable(ex).log("Unsupported type");
                 unsupportedMessage.add(vt);
             }
         }
diff --git a/src/java/org/apache/poi/hssf/dev/BiffViewer.java b/src/java/org/apache/poi/hssf/dev/BiffViewer.java
index 998df2f..4adbeda 100644
--- a/src/java/org/apache/poi/hssf/dev/BiffViewer.java
+++ b/src/java/org/apache/poi/hssf/dev/BiffViewer.java
@@ -31,6 +31,8 @@
 import java.util.ArrayList;
 import java.util.List;
 
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.apache.poi.hssf.record.*;
 import org.apache.poi.hssf.record.RecordInputStream.LeftoverDataException;
 import org.apache.poi.hssf.record.chart.*;
@@ -46,18 +48,19 @@
 import org.apache.poi.util.HexDump;
 import org.apache.poi.util.IOUtils;
 import org.apache.poi.util.LittleEndian;
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
+import org.apache.poi.util.RecordFormatException;
 import org.apache.poi.util.StringUtil;
 import org.apache.poi.util.SuppressForbidden;
 
+import static org.apache.logging.log4j.util.Unbox.box;
+
 /**
  *  Utility for reading in BIFF8 records and displaying data from them.
  * @see        #main
  */
 public final class BiffViewer {
     private static final char[] NEW_LINE_CHARS = System.getProperty("line.separator").toCharArray();
-    private static final POILogger LOG = POILogFactory.getLogger(BiffViewer.class);
+    private static final Logger LOG = LogManager.getLogger(BiffViewer.class);
 
     private BiffViewer() {
         // no instances of this class
@@ -71,17 +74,17 @@
      * @param recListener the record listener to notify about read records
      * @param dumpInterpretedRecords if {@code true}, the read records will be written to the PrintWriter
      *
-     * @exception  org.apache.poi.util.RecordFormatException  on error processing the InputStream
+     * @exception  RecordFormatException  on error processing the InputStream
      */
     private static void createRecords(InputStream is, PrintWriter ps, BiffRecordListener recListener, boolean dumpInterpretedRecords)
-            throws org.apache.poi.util.RecordFormatException {
+            throws RecordFormatException {
         RecordInputStream recStream = new RecordInputStream(is);
         while (true) {
             boolean hasNext;
             try {
                 hasNext = recStream.hasNextRecord();
             } catch (LeftoverDataException e) {
-                LOG.log(POILogger.ERROR, "Discarding ", recStream.remaining(), " bytes and continuing", e);
+                LOG.atError().withThrowable(e).log("Discarding {} bytes and continuing", box(recStream.remaining()));
                 recStream.readRemainder();
                 hasNext = recStream.hasNextRecord();
             }
@@ -92,7 +95,7 @@
             if (recStream.getSid() == 0) {
                 continue;
             }
-            org.apache.poi.hssf.record.Record record;
+            Record record;
             if (dumpInterpretedRecords) {
                 record = createRecord (recStream);
                 if (record.getSid() == ContinueRecord.sid) {
@@ -116,7 +119,7 @@
      *  up non-debug operations.
      *
      */
-    private static org.apache.poi.hssf.record.Record createRecord(RecordInputStream in) {
+    private static Record createRecord(RecordInputStream in) {
         switch (in.getSid()) {
             case AreaFormatRecord.sid:        return new AreaFormatRecord(in);
             case AreaRecord.sid:              return new AreaRecord(in);
diff --git a/src/java/org/apache/poi/hssf/eventusermodel/FormatTrackingHSSFListener.java b/src/java/org/apache/poi/hssf/eventusermodel/FormatTrackingHSSFListener.java
index 16c7bdf..fcd4cdd 100644
--- a/src/java/org/apache/poi/hssf/eventusermodel/FormatTrackingHSSFListener.java
+++ b/src/java/org/apache/poi/hssf/eventusermodel/FormatTrackingHSSFListener.java
@@ -23,16 +23,19 @@
 import java.util.Locale;
 import java.util.Map;
 
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.apache.poi.hssf.record.CellValueRecordInterface;
 import org.apache.poi.hssf.record.ExtendedFormatRecord;
 import org.apache.poi.hssf.record.FormatRecord;
 import org.apache.poi.hssf.record.FormulaRecord;
 import org.apache.poi.hssf.record.NumberRecord;
+import org.apache.poi.hssf.record.Record;
 import org.apache.poi.hssf.usermodel.HSSFDataFormat;
 import org.apache.poi.hssf.usermodel.HSSFDataFormatter;
 import org.apache.poi.util.LocaleUtil;
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
+
+import static org.apache.logging.log4j.util.Unbox.box;
 
 /**
  * A proxy HSSFListener that keeps track of the document formatting records, and
@@ -40,7 +43,7 @@
  * ids.
  */
 public class FormatTrackingHSSFListener implements HSSFListener {
-	private static final POILogger LOG = POILogFactory.getLogger(FormatTrackingHSSFListener.class);
+	private static final Logger LOG = LogManager.getLogger(FormatTrackingHSSFListener.class);
 	private final HSSFListener _childListener;
 	private final HSSFDataFormatter _formatter;
 	private final NumberFormat _defaultFormat;
@@ -83,7 +86,7 @@
 	 * Process this record ourselves, and then pass it on to our child listener
 	 */
 	@Override
-    public void processRecord(org.apache.poi.hssf.record.Record record) {
+    public void processRecord(Record record) {
 		// Handle it ourselves
 		processRecordInternally(record);
 
@@ -97,7 +100,7 @@
 	 *
 	 * @param record the record to be processed
 	 */
-	public void processRecordInternally(org.apache.poi.hssf.record.Record record) {
+	public void processRecordInternally(Record record) {
 		if (record instanceof FormatRecord) {
 			FormatRecord fr = (FormatRecord) record;
 			_customFormatRecords.put(Integer.valueOf(fr.getIndexCode()), fr);
@@ -154,8 +157,7 @@
 		if (formatIndex >= HSSFDataFormat.getNumberOfBuiltinBuiltinFormats()) {
 			FormatRecord tfr = _customFormatRecords.get(Integer.valueOf(formatIndex));
 			if (tfr == null) {
-				LOG.log( POILogger.ERROR, "Requested format at index ", formatIndex,
-						", but it wasn't found");
+				LOG.atError().log("Requested format at index {}, but it wasn't found", box(formatIndex));
 			} else {
 				format = tfr.getFormatString();
 			}
@@ -191,8 +193,7 @@
 	public int getFormatIndex(CellValueRecordInterface cell) {
 		ExtendedFormatRecord xfr = _xfRecords.get(cell.getXFIndex());
 		if (xfr == null) {
-			LOG.log( POILogger.ERROR, "Cell ", cell.getRow(), ",", cell.getColumn(),
-					" uses XF with index ", cell.getXFIndex(), ", but we don't have that");
+			LOG.atError().log("Cell {},{} uses XF with index {}, but we don't have that", box(cell.getRow()),box(cell.getColumn()),box(cell.getXFIndex()));
 			return -1;
 		}
 		return xfr.getFormatIndex();
diff --git a/src/java/org/apache/poi/hssf/model/InternalSheet.java b/src/java/org/apache/poi/hssf/model/InternalSheet.java
index c28dbee..efba5e7 100644
--- a/src/java/org/apache/poi/hssf/model/InternalSheet.java
+++ b/src/java/org/apache/poi/hssf/model/InternalSheet.java
@@ -21,6 +21,9 @@
 import java.util.Iterator;
 import java.util.List;
 
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+import org.apache.logging.log4j.message.SimpleMessage;
 import org.apache.poi.hssf.record.*;
 import org.apache.poi.hssf.record.aggregates.ChartSubstreamRecordAggregate;
 import org.apache.poi.hssf.record.aggregates.ColumnInfoRecordsAggregate;
@@ -34,14 +37,15 @@
 import org.apache.poi.hssf.record.aggregates.RecordAggregate.RecordVisitor;
 import org.apache.poi.hssf.record.aggregates.RowRecordsAggregate;
 import org.apache.poi.hssf.record.aggregates.WorksheetProtectionBlock;
+import org.apache.poi.hssf.usermodel.HSSFSheet;
 import org.apache.poi.ss.formula.FormulaShifter;
 import org.apache.poi.ss.util.CellRangeAddress;
 import org.apache.poi.ss.util.PaneInformation;
 import org.apache.poi.util.Internal;
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
 import org.apache.poi.util.RecordFormatException;
 
+import static org.apache.logging.log4j.util.Unbox.box;
+
 /**
  * Low level model implementation of a Sheet (one workbook contains many sheets)
  * This file contains the low level binary records starting at the sheets BOF and
@@ -53,8 +57,8 @@
  * Kit (Microsoft Press) and the documentation at http://sc.openoffice.org/excelfileformat.pdf
  * before even attempting to use this.
  *
- * @see org.apache.poi.hssf.model.InternalWorkbook
- * @see org.apache.poi.hssf.usermodel.HSSFSheet
+ * @see InternalWorkbook
+ * @see HSSFSheet
  */
 @Internal
 public final class InternalSheet {
@@ -63,7 +67,7 @@
     public static final short   TopMargin = 2;
     public static final short   BottomMargin = 3;
 
-    private static POILogger            log              = POILogFactory.getLogger(InternalSheet.class);
+    private static final Logger LOGGER = LogManager.getLogger(InternalSheet.class);
 
     private List<RecordBase>             _records;
     protected PrintGridlinesRecord       printGridlines;
@@ -115,8 +119,8 @@
      *
      * @return Sheet object with all values set to those read from the file
      *
-     * @see org.apache.poi.hssf.model.InternalWorkbook
-     * @see org.apache.poi.hssf.record.Record
+     * @see InternalWorkbook
+     * @see Record
      */
     public static InternalSheet createSheet(RecordStream rs) {
         return new InternalSheet(rs);
@@ -144,7 +148,7 @@
             // Not a supported type
             // Skip onto the EOF, then complain
             while (rs.hasNext()) {
-                org.apache.poi.hssf.record.Record rec = rs.getNext();
+                Record rec = rs.getNext();
                 if (rec instanceof EOFRecord) {
                     break;
                 }
@@ -229,7 +233,7 @@
                 continue;
             }
 
-            org.apache.poi.hssf.record.Record rec = rs.getNext();
+            Record rec = rs.getNext();
             if ( recSid == IndexRecord.sid ) {
                 // ignore INDEX record because it is only needed by Excel,
                 // and POI always re-calculates its contents
@@ -313,9 +317,7 @@
                 // Not clear which application wrote these files.
                 rra = new RowRecordsAggregate();
             } else {
-                if (log.check(POILogger.WARN)) {
-                    log.log(POILogger.WARN, "DIMENSION record not found even though row/cells present");
-                }
+                LOGGER.atWarn().log("DIMENSION record not found even though row/cells present");
                 // Not sure if any tools write files like this, but Excel reads them OK
             }
             dimsloc = findFirstRecordLocBySid(WindowTwoRecord.sid);
@@ -330,8 +332,7 @@
         // put merged cells table in the right place (regardless of where the first MergedCellsRecord was found */
         RecordOrderer.addNewSheetRecord(records, _mergedCellsTable);
         RecordOrderer.addNewSheetRecord(records, _protectionBlock);
-        if (log.check( POILogger.DEBUG ))
-            log.log(POILogger.DEBUG, "sheet createSheet (existing file) exited");
+        LOGGER.atDebug().log("sheet createSheet (existing file) exited");
     }
     private static void spillAggregate(RecordAggregate ra, final List<RecordBase> recs) {
         ra.visitContainedRecords(r -> recs.add(r));
@@ -351,12 +352,12 @@
 
     private static final class RecordCloner implements RecordVisitor {
 
-        private final List<org.apache.poi.hssf.record.Record> _destList;
+        private final List<Record> _destList;
 
-        public RecordCloner(List<org.apache.poi.hssf.record.Record> destList) {
+        public RecordCloner(List<Record> destList) {
             _destList = destList;
         }
-        public void visitRecord(org.apache.poi.hssf.record.Record r) {
+        public void visitRecord(Record r) {
             _destList.add(r.copy());
         }
     }
@@ -371,7 +372,7 @@
      * @return the cloned sheet
      */
     public InternalSheet cloneSheet() {
-        List<org.apache.poi.hssf.record.Record> clonedRecords = new ArrayList<>(_records.size());
+        List<Record> clonedRecords = new ArrayList<>(_records.size());
         for (int i = 0; i < _records.size(); i++) {
             RecordBase rb = _records.get(i);
             if (rb instanceof RecordAggregate) {
@@ -384,7 +385,7 @@
                  */
                 rb = new DrawingRecord();
             }
-            org.apache.poi.hssf.record.Record rec = ((org.apache.poi.hssf.record.Record) rb).copy();
+            Record rec = ((Record) rb).copy();
             clonedRecords.add(rec);
         }
         return createSheet(new RecordStream(clonedRecords, 0));
@@ -405,7 +406,7 @@
         _mergedCellsTable = new MergedCellsTable();
         List<RecordBase> records = new ArrayList<>(32);
 
-        log.log(POILogger.DEBUG, "Sheet createsheet from scratch called");
+        LOGGER.atDebug().log("Sheet createsheet from scratch called");
 
         records.add(createBOF());
 
@@ -452,7 +453,7 @@
         records.add(EOFRecord.instance);
 
         _records = records;
-        log.log(POILogger.DEBUG, "Sheet createsheet from scratch exit");
+        LOGGER.atDebug().log("Sheet createsheet from scratch exit");
     }
 
     public RowRecordsAggregate getRowsAggregate() {
@@ -533,24 +534,22 @@
      * @param lastrow the last row index
      * @param lastcol the last column index
      *
-     * @see org.apache.poi.hssf.record.DimensionsRecord
+     * @see DimensionsRecord
      */
     public void setDimensions(int firstrow, short firstcol, int lastrow, short lastcol)
     {
-        if (log.check( POILogger.DEBUG ))
-        {
-            log.log(POILogger.DEBUG, "Sheet.setDimensions");
-            log.log(POILogger.DEBUG,
-                    (new StringBuilder("firstrow")).append(firstrow)
-                        .append("firstcol").append(firstcol).append("lastrow")
-                        .append(lastrow).append("lastcol").append(lastcol)
-                        .toString());
-        }
+        LOGGER.atDebug().log("Sheet.setDimensions");
+        LOGGER.atDebug().log(() -> new SimpleMessage(
+                "firstrow" + firstrow +
+                        "firstcol" + firstcol +
+                        "lastrow" + lastrow +
+                        "lastcol" + lastcol
+        ));
         _dimensions.setFirstCol(firstcol);
         _dimensions.setFirstRow(firstrow);
         _dimensions.setLastCol(lastcol);
         _dimensions.setLastRow(lastrow);
-        log.log(POILogger.DEBUG, "Sheet.setDimensions exiting");
+        LOGGER.atDebug().log("Sheet.setDimensions exiting");
     }
 
     public void visitContainedRecords(RecordVisitor rv, int offset) {
@@ -566,7 +565,7 @@
                 RecordAggregate agg = (RecordAggregate) record;
                 agg.visitContainedRecords(ptv);
             } else {
-                ptv.visitRecord((org.apache.poi.hssf.record.Record) record);
+                ptv.visitRecord((Record) record);
             }
 
             // If the BOF record was just serialized then add the IndexRecord
@@ -628,9 +627,7 @@
      */
     public void addValueRecord(int row, CellValueRecordInterface col) {
 
-        if(log.check(POILogger.DEBUG)) {
-          log.log(POILogger.DEBUG, "add value record  row" + row);
-        }
+        LOGGER.atDebug().log("add value record row{}", box(row));
         DimensionsRecord d = _dimensions;
 
         if (col.getColumn() >= d.getLastCol()) {
@@ -649,11 +646,11 @@
      *
      * @param row - the row of the value record you wish to remove
      * @param col - a record supporting the CellValueRecordInterface.
-     * @see org.apache.poi.hssf.record.CellValueRecordInterface
+     * @see CellValueRecordInterface
      */
     public void removeValueRecord(int row, CellValueRecordInterface col) {
 
-        log.log(POILogger.DEBUG, "remove value record row "+row);
+        LOGGER.atDebug().log("remove value record row {}", box(row));
         _rowsAggregate.removeCell(col);
     }
 
@@ -669,8 +666,7 @@
 
     public void replaceValueRecord(CellValueRecordInterface newval) {
 
-        if (log.check( POILogger.DEBUG ))
-            log.log(POILogger.DEBUG, "replaceValueRecord ");
+        LOGGER.atDebug().log("replaceValueRecord ");
         //The ValueRecordsAggregate use a tree map underneath.
         //The tree Map uses the CellValueRecordInterface as both the
         //key and the value, if we dont do a remove, then
@@ -693,8 +689,7 @@
      */
 
     public void addRow(RowRecord row) {
-        if (log.check( POILogger.DEBUG ))
-            log.log(POILogger.DEBUG, "addRow ");
+        LOGGER.atDebug().log("addRow ");
         DimensionsRecord d = _dimensions;
 
         if (row.getRowNumber() >= d.getLastRow()) {
@@ -712,8 +707,7 @@
 
         _rowsAggregate.insertRow(row);
 
-        if (log.check( POILogger.DEBUG ))
-            log.log(POILogger.DEBUG, "exit addRow");
+        LOGGER.atDebug().log("exit addRow");
     }
 
     /**
@@ -1002,8 +996,8 @@
     /**
      * get the width of a given column in units of 1/256th of a character width
      * @param columnIndex index
-     * @see org.apache.poi.hssf.record.DefaultColWidthRecord
-     * @see org.apache.poi.hssf.record.ColumnInfoRecord
+     * @see DefaultColWidthRecord
+     * @see ColumnInfoRecord
      * @see #setColumnWidth(int, int)
      * @return column width in units of 1/256th of a character width
      */
@@ -1057,8 +1051,8 @@
     /**
      * Get the hidden property for a given column.
      * @param columnIndex column index
-     * @see org.apache.poi.hssf.record.DefaultColWidthRecord
-     * @see org.apache.poi.hssf.record.ColumnInfoRecord
+     * @see DefaultColWidthRecord
+     * @see ColumnInfoRecord
      * @see #setColumnHidden(int, boolean)
      * @return whether the column is hidden or not.
      */
@@ -1180,7 +1174,7 @@
     /**
      * Returns the active row
      *
-     * @see org.apache.poi.hssf.record.SelectionRecord
+     * @see SelectionRecord
      * @return row the active row index
      */
     public int getActiveCellRow() {
@@ -1194,7 +1188,7 @@
      * Sets the active row
      *
      * @param row the row index
-     * @see org.apache.poi.hssf.record.SelectionRecord
+     * @see SelectionRecord
      */
     public void setActiveCellRow(int row) {
         //shouldn't have a sheet w/o a SelectionRecord, but best to guard anyway
@@ -1204,7 +1198,7 @@
     }
 
     /**
-     * @see org.apache.poi.hssf.record.SelectionRecord
+     * @see SelectionRecord
      * @return column of the active cell
      */
     public short getActiveCellCol() {
@@ -1218,7 +1212,7 @@
      * Sets the active column
      *
      * @param col the column index
-     * @see org.apache.poi.hssf.record.SelectionRecord
+     * @see SelectionRecord
      */
     public void setActiveCellCol(short col) {
         //shouldn't have a sheet w/o a SelectionRecord, but best to guard anyway
@@ -1249,12 +1243,12 @@
      *
      * @return the matching record or {@code null} if it wasn't found
      */
-    public org.apache.poi.hssf.record.Record findFirstRecordBySid(short sid) {
+    public Record findFirstRecordBySid(short sid) {
         int ix = findFirstRecordLocBySid(sid);
         if (ix < 0) {
             return null;
         }
-        return (org.apache.poi.hssf.record.Record) _records.get(ix);
+        return (Record) _records.get(ix);
     }
 
     /**
@@ -1285,10 +1279,10 @@
         int max = _records.size();
         for (int i=0; i< max; i++) {
             Object rb = _records.get(i);
-            if (!(rb instanceof org.apache.poi.hssf.record.Record)) {
+            if (!(rb instanceof Record)) {
                 continue;
             }
-            org.apache.poi.hssf.record.Record record = (org.apache.poi.hssf.record.Record) rb;
+            Record record = (Record) rb;
             if (record.getSid() == sid) {
                 return i;
             }
diff --git a/src/java/org/apache/poi/hssf/model/InternalWorkbook.java b/src/java/org/apache/poi/hssf/model/InternalWorkbook.java
index e1d4f85..ef824fe 100644
--- a/src/java/org/apache/poi/hssf/model/InternalWorkbook.java
+++ b/src/java/org/apache/poi/hssf/model/InternalWorkbook.java
@@ -17,7 +17,7 @@
 
 package org.apache.poi.hssf.model;
 
-import static org.apache.poi.util.POILogger.DEBUG;
+import static org.apache.logging.log4j.util.Unbox.box;
 
 import java.security.AccessControlException;
 import java.util.ArrayList;
@@ -26,6 +26,8 @@
 import java.util.Map;
 import java.util.Map.Entry;
 
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.apache.poi.ddf.EscherBSERecord;
 import org.apache.poi.ddf.EscherBoolProperty;
 import org.apache.poi.ddf.EscherContainerRecord;
@@ -41,6 +43,7 @@
 import org.apache.poi.hssf.extractor.OldExcelExtractor;
 import org.apache.poi.hssf.record.*;
 import org.apache.poi.hssf.record.common.UnicodeString;
+import org.apache.poi.hssf.usermodel.HSSFWorkbook;
 import org.apache.poi.hssf.util.HSSFColor.HSSFColorPredefined;
 import org.apache.poi.poifs.crypt.CryptoFunctions;
 import org.apache.poi.ss.formula.EvaluationWorkbook.ExternalName;
@@ -58,8 +61,6 @@
 import org.apache.poi.ss.usermodel.Workbook;
 import org.apache.poi.util.Internal;
 import org.apache.poi.util.LocaleUtil;
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
 import org.apache.poi.util.RecordFormatException;
 
 /**
@@ -75,7 +76,7 @@
  * Kit (Microsoft Press) and the documentation at http://sc.openoffice.org/excelfileformat.pdf
  * before even attempting to use this.
  *
- * @see org.apache.poi.hssf.usermodel.HSSFWorkbook
+ * @see HSSFWorkbook
  */
 @Internal
 public final class InternalWorkbook {
@@ -103,7 +104,7 @@
      */
     public static final String OLD_WORKBOOK_DIR_ENTRY_NAME = "Book";
 
-    private static final POILogger LOG = POILogFactory.getLogger(InternalWorkbook.class);
+    private static final Logger LOG = LogManager.getLogger(InternalWorkbook.class);
 
     /**
      * constant used to set the "codepage" wherever "codepage" is set in records
@@ -179,15 +180,15 @@
      * @param recs an array of Record objects
      * @return Workbook object
      */
-    public static InternalWorkbook createWorkbook(List<org.apache.poi.hssf.record.Record> recs) {
-        LOG.log(DEBUG, "Workbook (readfile) created with reclen=", recs.size());
+    public static InternalWorkbook createWorkbook(List<Record> recs) {
+        LOG.atDebug().log("Workbook (readfile) created with reclen={}", box(recs.size()));
         InternalWorkbook retval = new InternalWorkbook();
-        List<org.apache.poi.hssf.record.Record> records = new ArrayList<>(recs.size() / 3);
+        List<Record> records = new ArrayList<>(recs.size() / 3);
         retval.records.setRecords(records);
 
         boolean eofPassed = false;
         for (int k = 0; k < recs.size(); k++) {
-            org.apache.poi.hssf.record.Record rec = recs.get(k);
+            Record rec = recs.get(k);
             String logObj;
             switch (rec.getSid()) {
 
@@ -239,7 +240,7 @@
                 case NameRecord.sid :
                 case SupBookRecord.sid :
                     // LinkTable can start with either of these
-                    LOG.log(DEBUG, "found SupBook record at " + k);
+                    LOG.atDebug().log("found SupBook record at {}", box(k));
                     retval.linkTable = new LinkTable(recs, k, retval.records, retval.commentRecords);
                     k+=retval.linkTable.getRecordCount() - 1;
                     continue;
@@ -300,7 +301,7 @@
             if (!eofPassed) {
                 records.add(rec);
             }
-            LOG.log(DEBUG, "found "+logObj+" record at " + k);
+            LOG.atDebug().log("found {} record at {}", logObj, box(k));
             if (rec.getSid() == EOFRecord.sid) {
                 eofPassed = true;
             }
@@ -314,7 +315,7 @@
         if (retval.windowOne == null) {
             retval.windowOne = createWindowOne();
         }
-        LOG.log(DEBUG, "exit create workbook from existing file function");
+        LOG.atDebug().log("exit create workbook from existing file function");
         return retval;
     }
 
@@ -325,10 +326,10 @@
      * @return an empty workbook object
      */
     public static InternalWorkbook createWorkbook() {
-        LOG.log( DEBUG, "creating new workbook from scratch" );
+        LOG.atDebug().log("creating new workbook from scratch");
 
         InternalWorkbook retval = new InternalWorkbook();
-        List<org.apache.poi.hssf.record.Record> records = new ArrayList<>(30);
+        List<Record> records = new ArrayList<>(30);
         retval.records.setRecords(records);
         List<FormatRecord> formats = retval.formats;
 
@@ -400,7 +401,7 @@
         records.add(InternalWorkbook.createExtendedSST());
 
         records.add(EOFRecord.instance);
-        LOG.log( DEBUG, "exit create new workbook from scratch" );
+        LOG.atDebug().log("exit create new workbook from scratch");
 
         return retval;
     }
@@ -523,7 +524,7 @@
      */
 
     public void setSheetBof(int sheetIndex, int pos) {
-        LOG.log(DEBUG, "setting bof for sheetnum =", sheetIndex, " at pos=", pos);
+        LOG.atDebug().log("setting bof for sheetnum ={} at pos={}", box(sheetIndex),box(pos));
 
         checkSheets(sheetIndex);
         getBoundSheetRec(sheetIndex)
@@ -605,7 +606,7 @@
         // also adjust order of Records, calculate the position of the Boundsheets via getBspos()...
         int initialBspos = records.getBspos();
         int pos0 = initialBspos - (boundsheets.size() - 1);
-        org.apache.poi.hssf.record.Record removed = records.get(pos0 + sheetNumber);
+        Record removed = records.get(pos0 + sheetNumber);
         records.remove(pos0 + sheetNumber);
 		records.add(pos0 + pos, removed);
         records.setBspos(initialBspos);
@@ -775,7 +776,7 @@
      * make the tabid record look like the current situation.
      */
     private void fixTabIdRecord() {
-        org.apache.poi.hssf.record.Record rec = records.get(records.getTabpos());
+        Record rec = records.get(records.getTabpos());
 
         // see bug 55982, quite a number of documents do not have a TabIdRecord and
         // thus there is no way to do the fixup here,
@@ -800,7 +801,7 @@
      */
 
     public int getNumSheets() {
-        LOG.log(DEBUG, "getNumSheets=", boundsheets.size());
+        LOG.atDebug().log("getNumSheets={}", box(boundsheets.size()));
         return boundsheets.size();
     }
 
@@ -811,7 +812,7 @@
      */
 
     public int getNumExFormats() {
-        LOG.log(DEBUG, "getXF=", numxfs);
+        LOG.atDebug().log("getXF={}", box(numxfs));
         return numxfs;
     }
 
@@ -886,7 +887,7 @@
         // Style records always follow after
         //  the ExtendedFormat records
         for(int i=records.getXfpos(); i<records.size(); i++) {
-            org.apache.poi.hssf.record.Record r = records.get(i);
+            Record r = records.get(i);
             if (r instanceof StyleRecord) {
                 StyleRecord sr = (StyleRecord)r;
                 if (sr.getXFIndex() == xfIndex) {
@@ -908,7 +909,7 @@
         // Style records always follow after
         //  the ExtendedFormat records
         for(int i=records.getXfpos(); i<records.size(); i++) {
-            org.apache.poi.hssf.record.Record r = records.get(i);
+            Record r = records.get(i);
             if (r instanceof StyleRecord) {
                 StyleRecord sr = (StyleRecord)r;
                 if (sr.getXFIndex() == oldXf) {
@@ -937,7 +938,7 @@
         int addAt = -1;
         for(int i=records.getXfpos(); i<records.size() &&
                 addAt == -1; i++) {
-            org.apache.poi.hssf.record.Record r = records.get(i);
+            Record r = records.get(i);
             if(r instanceof ExtendedFormatRecord ||
                     r instanceof StyleRecord) {
                 // Keep going
@@ -964,7 +965,7 @@
      */
 
     public int addSSTString(UnicodeString string) {
-        LOG.log(DEBUG, "insert to sst string='", string);
+        LOG.atDebug().log("insert to sst string='{}'", string);
         if (sst == null) {
             insertSST();
         }
@@ -982,7 +983,7 @@
         }
         UnicodeString retval = sst.getString(str);
 
-        LOG.log(DEBUG, "Returning SST for index=", str, " String= ", retval);
+        LOG.atDebug().log("Returning SST for index={} String= {}", box(str),retval);
         return retval;
     }
 
@@ -990,11 +991,11 @@
      * use this function to add a Shared String Table to an existing sheet (say
      * generated by a different java api) without an sst....
      * @see #createExtendedSST()
-     * @see org.apache.poi.hssf.record.SSTRecord
+     * @see SSTRecord
      */
 
     public void insertSST() {
-        LOG.log(DEBUG, "creating new SST via insertSST!");
+        LOG.atDebug().log("creating new SST via insertSST!");
 
         sst = new SSTRecord();
         records.add(records.size() - 1, createExtendedSST());
@@ -1009,14 +1010,14 @@
      * @return the length of serialized bytes
      */
     public int serialize( int offset, byte[] data ) {
-        LOG.log( DEBUG, "Serializing Workbook with offsets" );
+        LOG.atDebug().log("Serializing Workbook with offsets");
 
         int pos = 0;
 
         SSTRecord lSST = null;
         int sstPos = 0;
         boolean wroteBoundSheets = false;
-        for ( org.apache.poi.hssf.record.Record record : records.getRecords() ) {
+        for ( Record record : records.getRecords() ) {
             int len = 0;
             if (record instanceof SSTRecord) {
                 lSST = (SSTRecord)record;
@@ -1038,7 +1039,7 @@
             pos += len;
         }
 
-        LOG.log( DEBUG, "Exiting serialize workbook" );
+        LOG.atDebug().log("Exiting serialize workbook");
         return pos;
     }
 
@@ -1062,7 +1063,7 @@
         int retval = 0;
 
         SSTRecord lSST = null;
-        for ( org.apache.poi.hssf.record.Record record : records.getRecords() ) {
+        for ( Record record : records.getRecords() ) {
             if (record instanceof SSTRecord) {
                 lSST = (SSTRecord)record;
             }
@@ -1115,7 +1116,7 @@
 
             retval.setUsername(username);
         } catch (AccessControlException e) {
-            LOG.log(POILogger.WARN, "can't determine user.name", e);
+            LOG.atWarn().withThrowable(e).log("can't determine user.name");
             // AccessControlException can occur in a restricted context
             // (client applet/jws application or restricted security server)
             retval.setUsername(defaultUserName);
@@ -1426,8 +1427,8 @@
      * Always sets the sheet's bof to 0.  You'll need to set that yourself.
      * @param id either sheet 0,1 or 2.
      * @return record containing a BoundSheetRecord
-     * @see org.apache.poi.hssf.record.BoundSheetRecord
-     * @see org.apache.poi.hssf.record.Record
+     * @see BoundSheetRecord
+     * @see Record
      */
     private static BoundSheetRecord createBoundSheet(int id) {
         return new BoundSheetRecord("Sheet" + (id+1));
@@ -1707,8 +1708,8 @@
      * Creates a FormatRecord, inserts it, and returns the index code.
      * @param formatString the format string
      * @return the index code of the format record.
-     * @see org.apache.poi.hssf.record.FormatRecord
-     * @see org.apache.poi.hssf.record.Record
+     * @see FormatRecord
+     * @see Record
      */
     public int createFormat(String formatString) {
 
@@ -1734,8 +1735,8 @@
      *
      * @return the matching record or {@code null} if it wasn't found
      */
-    public org.apache.poi.hssf.record.Record findFirstRecordBySid(short sid) {
-        for (org.apache.poi.hssf.record.Record record : records.getRecords() ) {
+    public Record findFirstRecordBySid(short sid) {
+        for (Record record : records.getRecords() ) {
             if (record.getSid() == sid) {
                 return record;
             }
@@ -1750,7 +1751,7 @@
      */
     public int findFirstRecordLocBySid(short sid) {
         int index = 0;
-        for (org.apache.poi.hssf.record.Record record : records.getRecords() ) {
+        for (Record record : records.getRecords() ) {
             if (record.getSid() == sid) {
                 return index;
             }
@@ -1767,9 +1768,9 @@
      *
      * @return the matching record or {@code null} if it wasn't found
      */
-    public org.apache.poi.hssf.record.Record findNextRecordBySid(short sid, int pos) {
+    public Record findNextRecordBySid(short sid, int pos) {
         int matches = 0;
-        for (org.apache.poi.hssf.record.Record record : records.getRecords() ) {
+        for (Record record : records.getRecords() ) {
             if (record.getSid() == sid && matches++ == pos) {
                 return record;
             }
@@ -1782,7 +1783,7 @@
         return hyperlinks;
     }
 
-    public List<org.apache.poi.hssf.record.Record> getRecords() {
+    public List<Record> getRecords() {
         return records.getRecords();
     }
 
@@ -1806,7 +1807,7 @@
         PaletteRecord palette;
         int palettePos = records.getPalettepos();
         if (palettePos != -1) {
-            org.apache.poi.hssf.record.Record rec = records.get(palettePos);
+            Record rec = records.get(palettePos);
             if (rec instanceof PaletteRecord) {
                 palette = (PaletteRecord) rec;
             } else {
@@ -1833,7 +1834,7 @@
         }
 
         // Need to find a DrawingGroupRecord that contains a EscherDggRecord
-        for(org.apache.poi.hssf.record.Record r : records.getRecords() ) {
+        for(Record r : records.getRecords() ) {
             if (!(r instanceof DrawingGroupRecord)) {
                 continue;
             }
@@ -2207,7 +2208,7 @@
      *
      * @return a new RecalcIdRecord
      *
-     * @see org.apache.poi.hssf.usermodel.HSSFWorkbook#setForceFormulaRecalculation(boolean)
+     * @see HSSFWorkbook#setForceFormulaRecalculation(boolean)
      */
     public RecalcIdRecord getRecalcId(){
         RecalcIdRecord record = (RecalcIdRecord)findFirstRecordBySid(RecalcIdRecord.sid);
diff --git a/src/java/org/apache/poi/hssf/record/CFRule12Record.java b/src/java/org/apache/poi/hssf/record/CFRule12Record.java
index 3106ded..e1a3fc5 100644
--- a/src/java/org/apache/poi/hssf/record/CFRule12Record.java
+++ b/src/java/org/apache/poi/hssf/record/CFRule12Record.java
@@ -40,7 +40,8 @@
 import org.apache.poi.ss.util.CellRangeAddress;
 import org.apache.poi.util.IOUtils;
 import org.apache.poi.util.LittleEndianOutput;
-import org.apache.poi.util.POILogger;
+
+import static org.apache.logging.log4j.util.Unbox.box;
 
 /**
  * Conditional Formatting v12 Rule Record (0x087A).
@@ -285,7 +286,7 @@
             template_params = IOUtils.safelyAllocate(template_param_length, MAX_RECORD_LENGTH);
             in.readFully(template_params);
         } else {
-            LOG.log(POILogger.WARN, "CF Rule v12 template params length should be 0 or 16, found " + template_param_length);
+            LOG.atWarn().log("CF Rule v12 template params length should be 0 or 16, found {}", box(template_param_length));
             in.readRemainder();
         }
 
diff --git a/src/java/org/apache/poi/hssf/record/CFRuleBase.java b/src/java/org/apache/poi/hssf/record/CFRuleBase.java
index 71f52a0..22ee40f 100644
--- a/src/java/org/apache/poi/hssf/record/CFRuleBase.java
+++ b/src/java/org/apache/poi/hssf/record/CFRuleBase.java
@@ -20,6 +20,8 @@
 import java.util.Map;
 import java.util.function.Supplier;
 
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.apache.poi.hssf.model.HSSFFormulaParser;
 import org.apache.poi.hssf.record.cf.BorderFormatting;
 import org.apache.poi.hssf.record.cf.FontFormatting;
@@ -32,8 +34,6 @@
 import org.apache.poi.util.BitFieldFactory;
 import org.apache.poi.util.GenericRecordUtil;
 import org.apache.poi.util.LittleEndianOutput;
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
 
 /**
  * Conditional Formatting Rules. This can hold old-style rules
@@ -95,7 +95,7 @@
     public static final int TEMPLATE_ABOVE_OR_EQUAL_TO_AVERAGE = 0x001D;
     public static final int TEMPLATE_BELOW_OR_EQUAL_TO_AVERAGE = 0x001E;
 
-    protected static final POILogger LOG = POILogFactory.getLogger(CFRuleBase.class);
+    protected static final Logger LOG = LogManager.getLogger(CFRuleBase.class);
 
     static final BitField modificationBits = bf(0x003FFFFF); // Bits: font,align,bord,patt,prot
     static final BitField alignHor         = bf(0x00000001); // 0 = Horizontal alignment modified
diff --git a/src/java/org/apache/poi/hssf/record/DimensionsRecord.java b/src/java/org/apache/poi/hssf/record/DimensionsRecord.java
index 6f64b61..b12d008 100644
--- a/src/java/org/apache/poi/hssf/record/DimensionsRecord.java
+++ b/src/java/org/apache/poi/hssf/record/DimensionsRecord.java
@@ -22,10 +22,10 @@
 import java.util.Map;
 import java.util.function.Supplier;
 
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.apache.poi.util.GenericRecordUtil;
 import org.apache.poi.util.LittleEndianOutput;
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
 
 /**
  * Provides the minumum and maximum bounds of a sheet.
@@ -35,7 +35,7 @@
 
 public final class DimensionsRecord extends StandardRecord {
 
-    private static final POILogger LOG = POILogFactory.getLogger(DimensionsRecord.class);
+    private static final Logger LOG = LogManager.getLogger(DimensionsRecord.class);
 
     public static final short sid = 0x200;
     private int               field_1_first_row;
@@ -63,7 +63,7 @@
         field_5_zero      = in.readShort();
         //POI-61045 -- in practice, there can be an extra 2 bytes
         if (in.available() == 2) {
-            LOG.log(POILogger.INFO, "DimensionsRecord has extra 2 bytes.");
+            LOG.atInfo().log("DimensionsRecord has extra 2 bytes.");
             in.readShort();
         }
     }
diff --git a/src/java/org/apache/poi/hssf/record/EmbeddedObjectRefSubRecord.java b/src/java/org/apache/poi/hssf/record/EmbeddedObjectRefSubRecord.java
index bffc37d..ab5d387 100644
--- a/src/java/org/apache/poi/hssf/record/EmbeddedObjectRefSubRecord.java
+++ b/src/java/org/apache/poi/hssf/record/EmbeddedObjectRefSubRecord.java
@@ -21,6 +21,8 @@
 import java.util.Map;
 import java.util.function.Supplier;
 
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.apache.poi.ss.formula.ptg.Area3DPtg;
 import org.apache.poi.ss.formula.ptg.AreaPtg;
 import org.apache.poi.ss.formula.ptg.Ptg;
@@ -32,18 +34,18 @@
 import org.apache.poi.util.LittleEndianInput;
 import org.apache.poi.util.LittleEndianInputStream;
 import org.apache.poi.util.LittleEndianOutput;
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
 import org.apache.poi.util.RecordFormatException;
 import org.apache.poi.util.StringUtil;
 
+import static org.apache.logging.log4j.util.Unbox.box;
+
 /**
  * ftPictFmla (0x0009)<p>
  * A sub-record within the OBJ record which stores a reference to an object
  * stored in a separate entry within the OLE2 compound file.
  */
 public final class EmbeddedObjectRefSubRecord extends SubRecord {
-	private static final POILogger LOG = POILogFactory.getLogger(EmbeddedObjectRefSubRecord.class);
+	private static final Logger LOG = LogManager.getLogger(EmbeddedObjectRefSubRecord.class);
 	//arbitrarily selected; may need to increase
 	private static final int MAX_RECORD_LENGTH = 100_000;
 
@@ -157,7 +159,7 @@
 		int nUnexpectedPadding = remaining - dataLenAfterFormula;
 
 		if (nUnexpectedPadding > 0) {
-			LOG.log( POILogger.ERROR, "Discarding ", nUnexpectedPadding, " unexpected padding bytes");
+			LOG.atError().log("Discarding {} unexpected padding bytes", box(nUnexpectedPadding));
 			readRawData(in, nUnexpectedPadding);
 			remaining-=nUnexpectedPadding;
 		}
diff --git a/src/java/org/apache/poi/hssf/record/FeatRecord.java b/src/java/org/apache/poi/hssf/record/FeatRecord.java
index 22a3e89..f5850bf 100644
--- a/src/java/org/apache/poi/hssf/record/FeatRecord.java
+++ b/src/java/org/apache/poi/hssf/record/FeatRecord.java
@@ -21,6 +21,8 @@
 import java.util.function.Supplier;
 import java.util.stream.Stream;
 
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.apache.poi.hssf.record.common.FeatFormulaErr2;
 import org.apache.poi.hssf.record.common.FeatProtection;
 import org.apache.poi.hssf.record.common.FeatSmartTag;
@@ -29,8 +31,8 @@
 import org.apache.poi.ss.util.CellRangeAddress;
 import org.apache.poi.util.GenericRecordUtil;
 import org.apache.poi.util.LittleEndianOutput;
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
+
+import static org.apache.logging.log4j.util.Unbox.box;
 
 /**
  * Title: Feat (Feature) Record
@@ -39,8 +41,8 @@
  *  up with a {@link FeatHdrRecord}.
  */
 public final class FeatRecord extends StandardRecord {
-    private static final POILogger LOG = POILogFactory.getLogger(FeatRecord.class);
-    public static final short sid = 0x0868;
+    private static final Logger LOG = LogManager.getLogger(FeatRecord.class);
+	public static final short sid = 0x0868;
     // SIDs from newer versions
     public static final short v11_sid = 0x0872;
     public static final short v12_sid = 0x0878;
@@ -108,7 +110,7 @@
 			sharedFeature = new FeatSmartTag(in);
 			break;
 		default:
-			LOG.log( POILogger.ERROR, "Unknown Shared Feature ", isf_sharedFeatureType, " found!");
+			LOG.atError().log("Unknown Shared Feature {} found!", box(isf_sharedFeatureType));
 		}
 	}
 
diff --git a/src/java/org/apache/poi/hssf/record/FormatRecord.java b/src/java/org/apache/poi/hssf/record/FormatRecord.java
index 24063ff..7b2714b 100644
--- a/src/java/org/apache/poi/hssf/record/FormatRecord.java
+++ b/src/java/org/apache/poi/hssf/record/FormatRecord.java
@@ -21,19 +21,22 @@
 import java.util.Map;
 import java.util.function.Supplier;
 
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+import org.apache.poi.hssf.model.InternalWorkbook;
 import org.apache.poi.util.GenericRecordUtil;
 import org.apache.poi.util.LittleEndianConsts;
 import org.apache.poi.util.LittleEndianOutput;
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
 import org.apache.poi.util.StringUtil;
 
+import static org.apache.logging.log4j.util.Unbox.box;
+
 /**
  * Describes a number format -- those goofy strings like $(#,###)
  */
 public final class FormatRecord extends StandardRecord {
 
-    private static final POILogger LOG = POILogFactory.getLogger(FormatRecord.class);
+    private static final Logger LOG = LogManager.getLogger(FormatRecord.class);
 
     public static final short sid = 0x041E;
 
@@ -70,7 +73,7 @@
      * get the format index code (for built in formats)
      *
      * @return the format index code
-     * @see org.apache.poi.hssf.model.InternalWorkbook
+     * @see InternalWorkbook
      */
     public int getIndexCode() {
         return field_1_index_code;
@@ -149,7 +152,7 @@
         }
 
         if (ris.available() > 0) {
-            LOG.log(POILogger.INFO, "FormatRecord has ", ris.available(), " unexplained bytes. Silently skipping");
+            LOG.atInfo().log("FormatRecord has {} unexplained bytes. Silently skipping", box(ris.available()));
             //swallow what's left
             while (ris.available() > 0) {
                 ris.readByte();
diff --git a/src/java/org/apache/poi/hssf/record/HyperlinkRecord.java b/src/java/org/apache/poi/hssf/record/HyperlinkRecord.java
index 1c24d00..78bda25 100644
--- a/src/java/org/apache/poi/hssf/record/HyperlinkRecord.java
+++ b/src/java/org/apache/poi/hssf/record/HyperlinkRecord.java
@@ -17,24 +17,26 @@
 
 package org.apache.poi.hssf.record;
 
+import static org.apache.logging.log4j.util.Unbox.box;
 import static org.apache.poi.hpsf.ClassIDPredefined.FILE_MONIKER;
 import static org.apache.poi.hpsf.ClassIDPredefined.STD_MONIKER;
 import static org.apache.poi.hpsf.ClassIDPredefined.URL_MONIKER;
 import static org.apache.poi.util.GenericRecordUtil.getBitsAsString;
+import static org.apache.poi.util.HexDump.toHex;
 
 import java.util.Map;
 import java.util.function.Supplier;
 
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.apache.poi.hpsf.ClassID;
+import org.apache.poi.hpsf.ClassIDPredefined;
 import org.apache.poi.ss.util.CellRangeAddress;
 import org.apache.poi.util.GenericRecordUtil;
-import org.apache.poi.util.HexDump;
 import org.apache.poi.util.HexRead;
 import org.apache.poi.util.IOUtils;
 import org.apache.poi.util.LittleEndianInput;
 import org.apache.poi.util.LittleEndianOutput;
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
 import org.apache.poi.util.RecordFormatException;
 import org.apache.poi.util.StringUtil;
 
@@ -45,7 +47,7 @@
  */
 public final class HyperlinkRecord extends StandardRecord {
     public static final short sid = 0x01B8;
-    private static final POILogger LOG = POILogFactory.getLogger(HyperlinkRecord.class);
+    private static final Logger LOG = LogManager.getLogger(HyperlinkRecord.class);
     //arbitrarily selected; may need to increase
     private static final int MAX_RECORD_LENGTH = 100_000;
 
@@ -184,7 +186,7 @@
     }
 
     /**
-     * @return 16-byte guid identifier Seems to always equal {@link org.apache.poi.hpsf.ClassIDPredefined#STD_MONIKER}
+     * @return 16-byte guid identifier Seems to always equal {@link ClassIDPredefined#STD_MONIKER}
      */
     ClassID getGuid() {
         return _guid;
@@ -403,10 +405,7 @@
         }
 
         if (in.remaining() > 0) {
-           LOG.log(POILogger.WARN,
-                 "Hyperlink data remains: " + in.remaining() +
-                 " : " +HexDump.toHex(in.readRemainder())
-           );
+            LOG.atWarn().log("Hyperlink data remains: {} : {}", box(in.remaining()), toHex(in.readRemainder()));
         }
     }
 
diff --git a/src/java/org/apache/poi/hssf/record/LabelRecord.java b/src/java/org/apache/poi/hssf/record/LabelRecord.java
index f3ac972..b212860 100644
--- a/src/java/org/apache/poi/hssf/record/LabelRecord.java
+++ b/src/java/org/apache/poi/hssf/record/LabelRecord.java
@@ -20,20 +20,22 @@
 import java.util.Map;
 import java.util.function.Supplier;
 
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.apache.poi.util.GenericRecordUtil;
-import org.apache.poi.util.HexDump;
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
 import org.apache.poi.util.RecordFormatException;
 
+import static org.apache.logging.log4j.util.Unbox.box;
+import static org.apache.poi.util.HexDump.toHex;
+
 /**
  * Label Record (0x0204) - read only support for strings stored directly in the cell...
  * Don't use this (except to read), use LabelSST instead
  *
- * @see org.apache.poi.hssf.record.LabelSSTRecord
+ * @see LabelSSTRecord
  */
 public final class LabelRecord extends Record implements CellValueRecordInterface {
-    private static final POILogger LOG = POILogFactory.getLogger(LabelRecord.class);
+    private static final Logger LOG = LogManager.getLogger(LabelRecord.class);
 
     public static final short sid = 0x0204;
 
@@ -77,10 +79,7 @@
         }
 
         if (in.remaining() > 0) {
-           LOG.log(POILogger.INFO,
-                   "LabelRecord data remains: ", in.remaining(),
-                           " : ", HexDump.toHex(in.readRemainder())
-           );
+            LOG.atInfo().log("LabelRecord data remains: {} : {}", box(in.remaining()), toHex(in.readRemainder()));
         }
     }
 
diff --git a/src/java/org/apache/poi/hssf/record/OldLabelRecord.java b/src/java/org/apache/poi/hssf/record/OldLabelRecord.java
index dd59ca2..e393c8e 100644
--- a/src/java/org/apache/poi/hssf/record/OldLabelRecord.java
+++ b/src/java/org/apache/poi/hssf/record/OldLabelRecord.java
@@ -20,20 +20,22 @@
 import java.util.Map;
 import java.util.function.Supplier;
 
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.apache.poi.util.GenericRecordUtil;
-import org.apache.poi.util.HexDump;
 import org.apache.poi.util.IOUtils;
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
 import org.apache.poi.util.RecordFormatException;
 
+import static org.apache.logging.log4j.util.Unbox.box;
+import static org.apache.poi.util.HexDump.toHex;
+
 /**
  * Biff2 - Biff 4 Label Record (0x0004 / 0x0204) - read only support for
  *  strings stored directly in the cell, from the older file formats that
  *  didn't use {@link LabelSSTRecord}
  */
 public final class OldLabelRecord extends OldCellRecord {
-    private static final POILogger LOG = POILogFactory.getLogger(OldLabelRecord.class);
+    private static final Logger LOG = LogManager.getLogger(OldLabelRecord.class);
     //arbitrarily set, may need to increase
     private static final int MAX_RECORD_LENGTH = 100_000;
 
@@ -62,10 +64,7 @@
         in.read(field_5_bytes, 0, field_4_string_len);
 
         if (in.remaining() > 0) {
-            LOG.log(POILogger.INFO,
-                    "LabelRecord data remains: ", in.remaining(),
-                    " : ", HexDump.toHex(in.readRemainder())
-                    );
+            LOG.atInfo().log("LabelRecord data remains: {} : {}", box(in.remaining()), toHex(in.readRemainder()));
         }
     }
 
diff --git a/src/java/org/apache/poi/hssf/record/SSTDeserializer.java b/src/java/org/apache/poi/hssf/record/SSTDeserializer.java
index bcd6452..6b3bce3 100644
--- a/src/java/org/apache/poi/hssf/record/SSTDeserializer.java
+++ b/src/java/org/apache/poi/hssf/record/SSTDeserializer.java
@@ -19,10 +19,12 @@
 
 package org.apache.poi.hssf.record;
 
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.apache.poi.hssf.record.common.UnicodeString;
 import org.apache.poi.util.IntMapper;
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
+
+import static org.apache.logging.log4j.util.Unbox.box;
 
 /**
  * Handles the task of deserializing a SST string.  The two main entry points are
@@ -32,7 +34,7 @@
  */
 class SSTDeserializer
 {
-	private static final POILogger LOG = POILogFactory.getLogger(SSTDeserializer.class);
+	private static final Logger LOG = LogManager.getLogger(SSTDeserializer.class);
     private IntMapper<UnicodeString> strings;
 
     public SSTDeserializer( IntMapper<UnicodeString> strings )
@@ -51,7 +53,7 @@
          // Extract exactly the count of strings from the SST record.
          UnicodeString str;
           if (in.available() == 0 && !in.hasNextRecord()) {
-              LOG.log(POILogger.ERROR, "Ran out of data before creating all the strings! String at index ", i);
+              LOG.atError().log("Ran out of data before creating all the strings! String at index {}", box(i));
               str = new UnicodeString("");
           } else {
               str = new UnicodeString(in);
diff --git a/src/java/org/apache/poi/hssf/record/SupBookRecord.java b/src/java/org/apache/poi/hssf/record/SupBookRecord.java
index c9ff27f..2d610ac 100644
--- a/src/java/org/apache/poi/hssf/record/SupBookRecord.java
+++ b/src/java/org/apache/poi/hssf/record/SupBookRecord.java
@@ -20,10 +20,10 @@
 import java.util.Map;
 import java.util.function.Supplier;
 
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.apache.poi.util.GenericRecordUtil;
 import org.apache.poi.util.LittleEndianOutput;
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
 import org.apache.poi.util.StringUtil;
 
 /**
@@ -32,7 +32,7 @@
  */
 public final class SupBookRecord extends StandardRecord {
 
-    private static final POILogger LOG = POILogFactory.getLogger(SupBookRecord.class);
+    private static final Logger LOG = LogManager.getLogger(SupBookRecord.class);
 
     public static final short sid = 0x01AE;
 
@@ -222,12 +222,12 @@
         		break;
         	case CH_LONG_VOLUME:
         		//Don't known to handle...
-        		LOG.log(POILogger.WARN, "Found unexpected key: ChLongVolume - IGNORING");
+        		LOG.atWarn().log("Found unexpected key: ChLongVolume - IGNORING");
         		break;
         	case CH_STARTUP_DIR:
         	case CH_ALT_STARTUP_DIR:
         	case CH_LIB_DIR:
-        		LOG.log(POILogger.WARN, "EXCEL.EXE path unkown - using this directoy instead: .");
+        		LOG.atWarn().log("EXCEL.EXE path unknown - using this directory instead: .");
         		sb.append(".").append(PATH_SEPERATOR);
         		break;
         	default:
diff --git a/src/java/org/apache/poi/hssf/record/aggregates/CFRecordsAggregate.java b/src/java/org/apache/poi/hssf/record/aggregates/CFRecordsAggregate.java
index 4ee339a..cd513e8 100644
--- a/src/java/org/apache/poi/hssf/record/aggregates/CFRecordsAggregate.java
+++ b/src/java/org/apache/poi/hssf/record/aggregates/CFRecordsAggregate.java
@@ -22,6 +22,8 @@
 import java.util.Map;
 import java.util.function.Supplier;
 
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.apache.poi.common.usermodel.GenericRecord;
 import org.apache.poi.hssf.model.RecordStream;
 import org.apache.poi.hssf.record.CFHeader12Record;
@@ -37,10 +39,10 @@
 import org.apache.poi.ss.util.CellRangeAddress;
 import org.apache.poi.util.GenericRecordJsonWriter;
 import org.apache.poi.util.GenericRecordUtil;
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
 import org.apache.poi.util.RecordFormatException;
 
+import static org.apache.logging.log4j.util.Unbox.box;
+
 /**
  * <p>CFRecordsAggregate - aggregates Conditional Formatting records CFHeaderRecord
  * and number of up CFRuleRecord records together to simplify access to them.</p>
@@ -52,7 +54,7 @@
 public final class CFRecordsAggregate extends RecordAggregate implements GenericRecord {
     /** Excel 97-2003 allows up to 3 conditional formating rules */
     private static final int MAX_97_2003_CONDTIONAL_FORMAT_RULES = 3;
-    private static final POILogger LOG = POILogFactory.getLogger(CFRecordsAggregate.class);
+    private static final Logger LOG = LogManager.getLogger(CFRecordsAggregate.class);
 
     private final CFHeaderBase header;
 
@@ -72,10 +74,9 @@
             throw new IllegalArgumentException("rules must not be null");
         }
         if(pRules.length > MAX_97_2003_CONDTIONAL_FORMAT_RULES) {
-            LOG.log(POILogger.WARN, "Excel versions before 2007 require that "
-                    + "No more than " + MAX_97_2003_CONDTIONAL_FORMAT_RULES
-                    + " rules may be specified, " + pRules.length + " were found,"
-                    + " this file will cause problems with old Excel versions");
+            LOG.atWarn().log("Excel versions before 2007 require that No more than " +
+                    MAX_97_2003_CONDTIONAL_FORMAT_RULES + " rules may be specified, {} were found, this file will " +
+                    "cause problems with old Excel versions", box(pRules.length));
         }
         if (pRules.length != pHeader.getNumberOfConditionalFormats()) {
             throw new RecordFormatException("Mismatch number of rules");
@@ -181,7 +182,7 @@
             throw new IllegalArgumentException("r must not be null");
         }
         if(rules.size() >= MAX_97_2003_CONDTIONAL_FORMAT_RULES) {
-            LOG.log(POILogger.WARN, "Excel versions before 2007 cannot cope with"
+            LOG.atWarn().log("Excel versions before 2007 cannot cope with"
                     + " any more than " + MAX_97_2003_CONDTIONAL_FORMAT_RULES
                     + " - this file will cause problems with old Excel versions");
         }
diff --git a/src/java/org/apache/poi/hssf/record/cf/ColorGradientFormatting.java b/src/java/org/apache/poi/hssf/record/cf/ColorGradientFormatting.java
index c46238a..ab463c9 100644
--- a/src/java/org/apache/poi/hssf/record/cf/ColorGradientFormatting.java
+++ b/src/java/org/apache/poi/hssf/record/cf/ColorGradientFormatting.java
@@ -21,6 +21,8 @@
 import java.util.function.Supplier;
 import java.util.stream.Stream;
 
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.apache.poi.common.Duplicatable;
 import org.apache.poi.common.usermodel.GenericRecord;
 import org.apache.poi.hssf.record.common.ExtendedColor;
@@ -30,8 +32,8 @@
 import org.apache.poi.util.GenericRecordUtil;
 import org.apache.poi.util.LittleEndianInput;
 import org.apache.poi.util.LittleEndianOutput;
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
+
+import static org.apache.logging.log4j.util.Unbox.box;
 
 /**
  * Color Gradient / Color Scale Conditional Formatting Rule Record.
@@ -39,7 +41,7 @@
  *  Color Scale in the UI)
  */
 public final class ColorGradientFormatting implements Duplicatable, GenericRecord {
-    private static final POILogger log = POILogFactory.getLogger(ColorGradientFormatting.class);
+    private static final Logger LOGGER = LogManager.getLogger(ColorGradientFormatting.class);
 
     private static final BitField clamp = BitFieldFactory.getInstance(0x01);
     private static final BitField background = BitFieldFactory.getInstance(0x02);
@@ -70,7 +72,7 @@
         int numI = in.readByte();
         int numG = in.readByte();
         if (numI != numG) {
-            log.log(POILogger.WARN, "Inconsistent Color Gradient defintion, found " + numI + " vs " + numG + " entries");
+            LOGGER.atWarn().log("Inconsistent Color Gradient definition, found {} vs {} entries", box(numI),box(numG));
         }
         options = in.readByte();
 
diff --git a/src/java/org/apache/poi/hssf/record/cf/DataBarFormatting.java b/src/java/org/apache/poi/hssf/record/cf/DataBarFormatting.java
index 7dd3fa0..5063cfe 100644
--- a/src/java/org/apache/poi/hssf/record/cf/DataBarFormatting.java
+++ b/src/java/org/apache/poi/hssf/record/cf/DataBarFormatting.java
@@ -17,11 +17,14 @@
 
 package org.apache.poi.hssf.record.cf;
 
+import static org.apache.logging.log4j.util.Unbox.box;
 import static org.apache.poi.util.GenericRecordUtil.getBitsAsString;
 
 import java.util.Map;
 import java.util.function.Supplier;
 
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.apache.poi.common.Duplicatable;
 import org.apache.poi.common.usermodel.GenericRecord;
 import org.apache.poi.hssf.record.common.ExtendedColor;
@@ -31,14 +34,12 @@
 import org.apache.poi.util.GenericRecordUtil;
 import org.apache.poi.util.LittleEndianInput;
 import org.apache.poi.util.LittleEndianOutput;
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
 
 /**
  * Data Bar Conditional Formatting Rule Record.
  */
 public final class DataBarFormatting implements Duplicatable, GenericRecord {
-    private static final POILogger LOG = POILogFactory.getLogger(DataBarFormatting.class);
+    private static final Logger LOG = LogManager.getLogger(DataBarFormatting.class);
 
     private static final BitField ICON_ONLY = BitFieldFactory.getInstance(0x01);
     private static final BitField REVERSED = BitFieldFactory.getInstance(0x04);
@@ -71,9 +72,9 @@
         percentMin = in.readByte();
         percentMax = in.readByte();
         if (percentMin < 0 || percentMin > 100)
-            LOG.log(POILogger.WARN, "Inconsistent Minimum Percentage found " + percentMin);
+            LOG.atWarn().log("Inconsistent Minimum Percentage found {}", box(percentMin));
         if (percentMax < 0 || percentMax > 100)
-            LOG.log(POILogger.WARN, "Inconsistent Maximum Percentage found " + percentMax);
+            LOG.atWarn().log("Inconsistent Maximum Percentage found {}", box(percentMax));
 
         color = new ExtendedColor(in);
         thresholdMin = new DataBarThreshold(in);
diff --git a/src/java/org/apache/poi/hssf/record/cf/IconMultiStateFormatting.java b/src/java/org/apache/poi/hssf/record/cf/IconMultiStateFormatting.java
index 616d3e0..ac2a42f 100644
--- a/src/java/org/apache/poi/hssf/record/cf/IconMultiStateFormatting.java
+++ b/src/java/org/apache/poi/hssf/record/cf/IconMultiStateFormatting.java
@@ -21,6 +21,8 @@
 import java.util.function.Supplier;
 import java.util.stream.Stream;
 
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.apache.poi.common.Duplicatable;
 import org.apache.poi.common.usermodel.GenericRecord;
 import org.apache.poi.ss.usermodel.IconMultiStateFormatting.IconSet;
@@ -30,14 +32,14 @@
 import org.apache.poi.util.GenericRecordUtil;
 import org.apache.poi.util.LittleEndianInput;
 import org.apache.poi.util.LittleEndianOutput;
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
+
+import static org.apache.logging.log4j.util.Unbox.box;
 
 /**
  * Icon / Multi-State Conditional Formatting Rule Record.
  */
 public final class IconMultiStateFormatting implements Duplicatable, GenericRecord {
-    private static final POILogger LOG = POILogFactory.getLogger(IconMultiStateFormatting.class);
+    private static final Logger LOG = LogManager.getLogger(IconMultiStateFormatting.class);
 
     private static BitField ICON_ONLY = BitFieldFactory.getInstance(0x01);
     private static BitField REVERSED = BitFieldFactory.getInstance(0x04);
@@ -67,7 +69,7 @@
         int set = in.readByte();
         iconSet = IconSet.byId(set);
         if (iconSet.num != num) {
-            LOG.log(POILogger.WARN, "Inconsistent Icon Set defintion, found " + iconSet + " but defined as " + num + " entries");
+            LOG.atWarn().log("Inconsistent Icon Set definition, found {} but defined as {} entries", iconSet, box(num));
         }
         options = in.readByte();
 
diff --git a/src/java/org/apache/poi/hssf/record/common/ExtRst.java b/src/java/org/apache/poi/hssf/record/common/ExtRst.java
index 1d8101b..bb409ed 100644
--- a/src/java/org/apache/poi/hssf/record/common/ExtRst.java
+++ b/src/java/org/apache/poi/hssf/record/common/ExtRst.java
@@ -22,19 +22,21 @@
 import java.util.function.Supplier;
 import java.util.stream.Stream;
 
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.apache.poi.common.usermodel.GenericRecord;
 import org.apache.poi.hssf.record.cont.ContinuableRecordOutput;
 import org.apache.poi.util.GenericRecordUtil;
 import org.apache.poi.util.IOUtils;
 import org.apache.poi.util.Internal;
 import org.apache.poi.util.LittleEndianInput;
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
 import org.apache.poi.util.StringUtil;
 
+import static org.apache.logging.log4j.util.Unbox.box;
+
 @Internal
 public class ExtRst implements Comparable<ExtRst>, GenericRecord {
-    private static final POILogger LOG = POILogFactory.getLogger(ExtRst.class);
+    private static final Logger LOG = LogManager.getLogger(ExtRst.class);
     //arbitrarily selected; may need to increase
     private static final int MAX_RECORD_LENGTH = 100_000;
 
@@ -78,7 +80,7 @@
 
         // Spot corrupt records
         if(reserved != 1) {
-            LOG.log(POILogger.WARN, "Warning - ExtRst has wrong magic marker, expecting 1 but found ", reserved, " - ignoring");
+            LOG.atWarn().log("ExtRst has wrong magic marker, expecting 1 but found {} - ignoring", box(reserved));
             // Grab all the remaining data, and ignore it
             for(int i=0; i<expectedLength-2; i++) {
                 in.readByte();
@@ -121,7 +123,7 @@
 
         int extraDataLength = runData - (numRuns*6);
         if(extraDataLength < 0) {
-            LOG.log( POILogger.WARN, "Warning - ExtRst overran by ",  (0-extraDataLength), " bytes");
+            LOG.atWarn().log("ExtRst overran by {} bytes", box(-extraDataLength));
             extraDataLength = 0;
         }
         extraData = IOUtils.safelyAllocate(extraDataLength, MAX_RECORD_LENGTH);
diff --git a/src/java/org/apache/poi/hssf/record/common/UnicodeString.java b/src/java/org/apache/poi/hssf/record/common/UnicodeString.java
index d6afa2a..d9b56d7 100644
--- a/src/java/org/apache/poi/hssf/record/common/UnicodeString.java
+++ b/src/java/org/apache/poi/hssf/record/common/UnicodeString.java
@@ -26,6 +26,8 @@
 import java.util.function.Supplier;
 import java.util.stream.Collectors;
 
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.apache.poi.common.Duplicatable;
 import org.apache.poi.common.usermodel.GenericRecord;
 import org.apache.poi.hssf.record.RecordInputStream;
@@ -34,8 +36,8 @@
 import org.apache.poi.util.BitField;
 import org.apache.poi.util.BitFieldFactory;
 import org.apache.poi.util.GenericRecordUtil;
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
+
+import static org.apache.logging.log4j.util.Unbox.box;
 
 /**
  * Unicode String - just standard fields that are in several records.
@@ -43,7 +45,7 @@
  * This is often called a XLUnicodeRichExtendedString in MS documentation.<p>
  */
 public class UnicodeString implements Comparable<UnicodeString>, Duplicatable, GenericRecord {
-    private static final POILogger LOG = POILogFactory.getLogger(UnicodeString.class);
+    private static final Logger LOG = LogManager.getLogger(UnicodeString.class);
 
     private static final BitField highByte  = BitFieldFactory.getInstance(0x1);
     // 0x2 is reserved
@@ -102,7 +104,7 @@
         if (isExtendedText() && (extensionLength > 0)) {
           field_5_ext_rst = new ExtRst(new ContinuableRecordInput(in), extensionLength);
           if(field_5_ext_rst.getDataSize()+4 != extensionLength) {
-             LOG.log(POILogger.WARN, "ExtRst was supposed to be " + extensionLength + " bytes long, but seems to actually be " + (field_5_ext_rst.getDataSize() + 4));
+              LOG.atWarn().log("ExtRst was supposed to be {} bytes long, but seems to actually be {}", box(extensionLength),box(field_5_ext_rst.getDataSize() + 4));
           }
         }
     }
diff --git a/src/java/org/apache/poi/hssf/usermodel/EscherGraphics.java b/src/java/org/apache/poi/hssf/usermodel/EscherGraphics.java
index fb58e04..4e3c4bd 100644
--- a/src/java/org/apache/poi/hssf/usermodel/EscherGraphics.java
+++ b/src/java/org/apache/poi/hssf/usermodel/EscherGraphics.java
@@ -17,10 +17,10 @@
 
 package org.apache.poi.hssf.usermodel;
 
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.apache.poi.hssf.util.HSSFColor;
 import org.apache.poi.util.NotImplemented;
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
 import org.apache.poi.util.SuppressForbidden;
 
 import java.awt.*;
@@ -60,7 +60,7 @@
  * </blockquote>
  */
 public class EscherGraphics extends Graphics {
-    private static final POILogger LOG = POILogFactory.getLogger(EscherGraphics.class);
+    private static final Logger LOG = LogManager.getLogger(EscherGraphics.class);
 
     private final HSSFShapeGroup escherGroup;
     private final HSSFWorkbook workbook;
@@ -135,14 +135,14 @@
     @NotImplemented
     public void clipRect(int x, int y, int width, int height)
     {
-        LOG.log(POILogger.WARN,"clipRect not supported");
+        LOG.atWarn().log("clipRect not supported");
     }
 
     @Override
     @NotImplemented
     public void copyArea(int x, int y, int width, int height, int dx, int dy)
     {
-        LOG.log(POILogger.WARN,"copyArea not supported");
+        LOG.atWarn().log("copyArea not supported");
     }
 
     @Override
@@ -162,7 +162,7 @@
     public void drawArc(int x, int y, int width, int height,
 				 int startAngle, int arcAngle)
     {
-        LOG.log(POILogger.WARN,"drawArc not supported");
+        LOG.atWarn().log("drawArc not supported");
     }
 
     @Override
@@ -173,7 +173,7 @@
 				      Color bgcolor,
 				      ImageObserver observer)
     {
-        LOG.log(POILogger.WARN,"drawImage not supported");
+        LOG.atWarn().log("drawImage not supported");
 
         return true;
     }
@@ -185,7 +185,7 @@
 				      int sx1, int sy1, int sx2, int sy2,
 				      ImageObserver observer)
     {
-        LOG.log(POILogger.WARN,"drawImage not supported");
+        LOG.atWarn().log("drawImage not supported");
         return true;
     }
 
@@ -266,14 +266,14 @@
     public void drawPolyline(int[] xPoints, int[] yPoints,
                              int nPoints)
     {
-        LOG.log(POILogger.WARN,"drawPolyline not supported");
+        LOG.atWarn().log("drawPolyline not supported");
     }
 
     @Override
     @NotImplemented
     public void drawRect(int x, int y, int width, int height)
     {
-        LOG.log(POILogger.WARN,"drawRect not supported");
+        LOG.atWarn().log("drawRect not supported");
     }
 
     @Override
@@ -281,7 +281,7 @@
     public void drawRoundRect(int x, int y, int width, int height,
 				       int arcWidth, int arcHeight)
     {
-        LOG.log(POILogger.WARN,"drawRoundRect not supported");
+        LOG.atWarn().log("drawRoundRect not supported");
     }
 
     @Override
@@ -349,16 +349,14 @@
     public void drawString(AttributedCharacterIterator iterator,
                                     int x, int y)
     {
-        if (LOG.check( POILogger.WARN ))
-            LOG.log(POILogger.WARN,"drawString not supported");
+        LOG.atWarn().log("drawString not supported");
     }
 
     @Override
     public void fillArc(int x, int y, int width, int height,
 				 int startAngle, int arcAngle)
     {
-        if (LOG.check( POILogger.WARN ))
-            LOG.log(POILogger.WARN,"fillArc not supported");
+        LOG.atWarn().log("fillArc not supported");
     }
 
     @Override
@@ -389,7 +387,7 @@
      * @param xPoints array of the <code>x</code> coordinates.
      * @param yPoints array of the <code>y</code> coordinates.
      * @param nPoints the total number of points in the polygon.
-     * @see   java.awt.Graphics#drawPolygon(int[], int[], int)
+     * @see   Graphics#drawPolygon(int[], int[], int)
      */
     @Override
     public void fillPolygon(int[] xPoints, int[] yPoints,
@@ -442,8 +440,7 @@
     public void fillRoundRect(int x, int y, int width, int height,
 				       int arcWidth, int arcHeight)
     {
-        if (LOG.check( POILogger.WARN ))
-            LOG.log(POILogger.WARN,"fillRoundRect not supported");
+        LOG.atWarn().log("fillRoundRect not supported");
     }
 
     @Override
@@ -488,7 +485,7 @@
     @NotImplemented
     public void setClip(Shape shape)
     {
-        LOG.log(POILogger.WARN,"setClip not supported");
+        LOG.atWarn().log("setClip not supported");
     }
 
     @Override
@@ -507,21 +504,21 @@
     @NotImplemented
     public void setPaintMode()
     {
-        LOG.log(POILogger.WARN,"setPaintMode not supported");
+        LOG.atWarn().log("setPaintMode not supported");
     }
 
     @Override
     @NotImplemented
     public void setXORMode(Color color)
     {
-        LOG.log(POILogger.WARN,"setXORMode not supported");
+        LOG.atWarn().log("setXORMode not supported");
     }
 
     @Override
     @NotImplemented
     public void translate(int x, int y)
     {
-        LOG.log(POILogger.WARN,"translate not supported");
+        LOG.atWarn().log("translate not supported");
     }
 
     public Color getBackground()
diff --git a/src/java/org/apache/poi/hssf/usermodel/EscherGraphics2d.java b/src/java/org/apache/poi/hssf/usermodel/EscherGraphics2d.java
index 6d631ef..a5e3516 100644
--- a/src/java/org/apache/poi/hssf/usermodel/EscherGraphics2d.java
+++ b/src/java/org/apache/poi/hssf/usermodel/EscherGraphics2d.java
@@ -17,17 +17,19 @@
 
 package org.apache.poi.hssf.usermodel;
 
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 
 import java.awt.*;
 import java.awt.font.FontRenderContext;
 import java.awt.font.GlyphVector;
 import java.awt.font.TextLayout;
 import java.awt.geom.AffineTransform;
+import java.awt.geom.Arc2D;
 import java.awt.geom.Area;
 import java.awt.geom.GeneralPath;
 import java.awt.geom.Line2D;
+import java.awt.geom.RoundRectangle2D;
 import java.awt.image.BufferedImage;
 import java.awt.image.BufferedImageOp;
 import java.awt.image.ImageObserver;
@@ -69,7 +71,7 @@
  * </blockquote>
  */
 public final class EscherGraphics2d extends Graphics2D {
-    private static final POILogger LOG = POILogFactory.getLogger(EscherGraphics2d.class);
+    private static final Logger LOG = LogManager.getLogger(EscherGraphics2d.class);
 
     private EscherGraphics _escherGraphics;
     private BufferedImage _img;
@@ -153,15 +155,14 @@
         }
         else
         {
-            if (LOG.check(POILogger.WARN))
-                LOG.log(POILogger.WARN, "draw not fully supported");
+            LOG.atWarn().log("draw not fully supported");
         }
     }
 
     public void drawArc(int x, int y, int width, int height,
 				 int startAngle, int arcAngle)
     {
-        draw(new java.awt.geom.Arc2D.Float(x, y, width, height, startAngle, arcAngle, 0));
+        draw(new Arc2D.Float(x, y, width, height, startAngle, arcAngle, 0));
     }
 
     public void drawGlyphVector(GlyphVector g, float x, float y)
@@ -172,22 +173,19 @@
     public boolean drawImage(Image image, int dx1, int dy1, int dx2, int dy2, int sx1, int sy1,
             int sx2, int sy2, Color bgColor, ImageObserver imageobserver)
     {
-        if (LOG.check( POILogger.WARN ))
-            LOG.log(POILogger.WARN,"drawImage() not supported");
+        LOG.atWarn().log("drawImage() not supported");
         return true;
     }
 
     public boolean drawImage(Image image, int dx1, int dy1, int dx2, int dy2, int sx1, int sy1,
             int sx2, int sy2, ImageObserver imageobserver)
     {
-        if (LOG.check( POILogger.WARN ))
-            LOG.log(POILogger.WARN,"drawImage() not supported");
+        LOG.atWarn().log("drawImage() not supported");
         return drawImage(image, dx1, dy1, dx2, dy2, sx1, sy1, sx2, sy2, null, imageobserver);
     }
     public boolean drawImage(Image image, int dx1, int dy1, int dx2, int dy2, Color bgColor, ImageObserver imageobserver)
     {
-        if (LOG.check( POILogger.WARN ))
-            LOG.log(POILogger.WARN,"drawImage() not supported");
+        LOG.atWarn().log("drawImage() not supported");
         return true;
     }
 
@@ -282,7 +280,7 @@
 
     public void drawRoundRect(int i, int j, int k, int l, int i1, int j1)
     {
-        draw(new java.awt.geom.RoundRectangle2D.Float(i, j, k, l, i1, j1));
+        draw(new RoundRectangle2D.Float(i, j, k, l, i1, j1));
     }
 
     public void drawString(String string, float x, float y)
@@ -311,13 +309,12 @@
 
     public void fill(Shape shape)
     {
-        if (LOG.check( POILogger.WARN ))
-            LOG.log(POILogger.WARN,"fill(Shape) not supported");
+        LOG.atWarn().log("fill(Shape) not supported");
     }
 
     public void fillArc(int i, int j, int k, int l, int i1, int j1)
     {
-        fill(new java.awt.geom.Arc2D.Float(i, j, k, l, i1, j1, 2));
+        fill(new Arc2D.Float(i, j, k, l, i1, j1, 2));
     }
 
     public void fillOval(int x, int y, int width, int height)
@@ -342,7 +339,7 @@
      * @param xPoints array of the <code>x</code> coordinates.
      * @param yPoints array of the <code>y</code> coordinates.
      * @param nPoints the total number of points in the polygon.
-     * @see   java.awt.Graphics#drawPolygon(int[], int[], int)
+     * @see   Graphics#drawPolygon(int[], int[], int)
      */
     public void fillPolygon(int[] xPoints, int[] yPoints, int nPoints)
     {
@@ -357,7 +354,7 @@
     public void fillRoundRect(int x, int y, int width, int height,
 				       int arcWidth, int arcHeight)
     {
-        fill(new java.awt.geom.RoundRectangle2D.Float(x, y, width, height, arcWidth, arcHeight));
+        fill(new RoundRectangle2D.Float(x, y, width, height, arcWidth, arcHeight));
     }
 
     public Color getBackground()
@@ -422,7 +419,7 @@
         return _paint;
     }
 
-    public Object getRenderingHint(java.awt.RenderingHints.Key key)
+    public Object getRenderingHint(RenderingHints.Key key)
     {
         return getG2D().getRenderingHint(key);
     }
@@ -510,7 +507,7 @@
         getEscherGraphics().setPaintMode();
     }
 
-    public void setRenderingHint(java.awt.RenderingHints.Key key, Object obj)
+    public void setRenderingHint(RenderingHints.Key key, Object obj)
     {
         getG2D().setRenderingHint(key, obj);
     }
@@ -545,18 +542,6 @@
         getTrans().concatenate(affinetransform);
     }
 
-//    Image transformImage(Image image, Rectangle rectangle, Rectangle rectangle1, ImageObserver imageobserver, Color color1)
-//    {
-//        logger.log(POILogger.WARN,"transformImage() not supported");
-//        return null;
-//    }
-//
-//    Image transformImage(Image image, int ai[], Rectangle rectangle, ImageObserver imageobserver, Color color1)
-//    {
-//        logger.log(POILogger.WARN,"transformImage() not supported");
-//        return null;
-//    }
-
     public void translate(double d, double d1)
     {
         getTrans().translate(d, d1);
diff --git a/src/java/org/apache/poi/hssf/usermodel/HSSFPatriarch.java b/src/java/org/apache/poi/hssf/usermodel/HSSFPatriarch.java
index c0aa36f..e5b6d66 100644
--- a/src/java/org/apache/poi/hssf/usermodel/HSSFPatriarch.java
+++ b/src/java/org/apache/poi/hssf/usermodel/HSSFPatriarch.java
@@ -57,7 +57,6 @@
  * little other than act as a container for other shapes and groups.
  */
 public final class HSSFPatriarch implements HSSFShapeContainer, Drawing<HSSFShape> {
-    // private static POILogger log = POILogFactory.getLogger(HSSFPatriarch.class);
     private final List<HSSFShape> _shapes = new ArrayList<>();
 
     private final EscherSpgrRecord _spgrRecord;
diff --git a/src/java/org/apache/poi/hssf/usermodel/HSSFPolygon.java b/src/java/org/apache/poi/hssf/usermodel/HSSFPolygon.java
index b56e105..430fe62 100644
--- a/src/java/org/apache/poi/hssf/usermodel/HSSFPolygon.java
+++ b/src/java/org/apache/poi/hssf/usermodel/HSSFPolygon.java
@@ -17,6 +17,8 @@
 
 package org.apache.poi.hssf.usermodel;
 
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.apache.poi.ddf.EscherArrayProperty;
 import org.apache.poi.ddf.EscherBoolProperty;
 import org.apache.poi.ddf.EscherClientDataRecord;
@@ -34,8 +36,6 @@
 import org.apache.poi.hssf.record.ObjRecord;
 import org.apache.poi.hssf.record.TextObjectRecord;
 import org.apache.poi.util.LittleEndian;
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
 
 /**
  *
@@ -43,7 +43,7 @@
 public class HSSFPolygon  extends HSSFSimpleShape {
     public static final short OBJECT_TYPE_MICROSOFT_OFFICE_DRAWING = 0x1E;
 
-    private static final POILogger LOG = POILogFactory.getLogger(HSSFPolygon.class);
+    private static final Logger LOG = LogManager.getLogger(HSSFPolygon.class);
 
     public HSSFPolygon(EscherContainerRecord spContainer, ObjRecord objRecord, TextObjectRecord _textObjectRecord) {
         super(spContainer, objRecord, _textObjectRecord);
@@ -174,11 +174,11 @@
      */
     public void setPoints(int[] xPoints, int[] yPoints) {
         if (xPoints.length != yPoints.length){
-        	LOG.log( POILogger.ERROR, "xPoint.length must be equal to yPoints.length");
+        	LOG.atError().log("xPoint.length must be equal to yPoints.length");
             return;
         }
         if (xPoints.length == 0){
-        	LOG.log( POILogger.ERROR, "HSSFPolygon must have at least one point");
+        	LOG.atError().log("HSSFPolygon must have at least one point");
         }
         EscherArrayProperty verticesProp = new EscherArrayProperty(EscherPropertyTypes.GEOMETRY__VERTICES, false, 0);
         verticesProp.setNumberOfElementsInArray(xPoints.length+1);
diff --git a/src/java/org/apache/poi/hssf/usermodel/HSSFShape.java b/src/java/org/apache/poi/hssf/usermodel/HSSFShape.java
index 7e575a6..92d66e1 100644
--- a/src/java/org/apache/poi/hssf/usermodel/HSSFShape.java
+++ b/src/java/org/apache/poi/hssf/usermodel/HSSFShape.java
@@ -20,6 +20,8 @@
 import java.io.ByteArrayOutputStream;
 import java.io.IOException;
 
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.apache.poi.ddf.EscherBoolProperty;
 import org.apache.poi.ddf.EscherChildAnchorRecord;
 import org.apache.poi.ddf.EscherClientAnchorRecord;
@@ -35,8 +37,6 @@
 import org.apache.poi.hssf.record.ObjRecord;
 import org.apache.poi.ss.usermodel.Shape;
 import org.apache.poi.util.LittleEndian;
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
 import org.apache.poi.util.StringUtil;
 
 /**
@@ -48,7 +48,7 @@
  * setFlipVertical() or setFlipHorizontally().
  */
 public abstract class HSSFShape implements Shape {
-    private static final POILogger LOG = POILogFactory.getLogger(HSSFShape.class);
+    private static final Logger LOG = LogManager.getLogger(HSSFShape.class);
 
     public static final int LINEWIDTH_ONE_PT = 12700;
     public static final int LINEWIDTH_DEFAULT = 9525;
@@ -374,7 +374,7 @@
             LittleEndian.putInt(property.getPropertyValue(), bos);
             return LittleEndian.getShort(bos.toByteArray(), 2);
         } catch (IOException e) {
-            LOG.log(POILogger.ERROR, "can't determine rotation degree", e);
+            LOG.atError().withThrowable(e).log("can't determine rotation degree");
             return 0;
         }
     }
diff --git a/src/java/org/apache/poi/hssf/usermodel/HSSFSheet.java b/src/java/org/apache/poi/hssf/usermodel/HSSFSheet.java
index 03d4f21..ad32e12 100644
--- a/src/java/org/apache/poi/hssf/usermodel/HSSFSheet.java
+++ b/src/java/org/apache/poi/hssf/usermodel/HSSFSheet.java
@@ -26,6 +26,9 @@
 import java.util.TreeMap;
 import java.util.TreeSet;
 
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+import org.apache.logging.log4j.message.SimpleMessage;
 import org.apache.poi.ddf.EscherRecord;
 import org.apache.poi.hssf.model.DrawingManager2;
 import org.apache.poi.hssf.model.HSSFFormulaParser;
@@ -64,7 +67,10 @@
 import org.apache.poi.ss.usermodel.CellStyle;
 import org.apache.poi.ss.usermodel.DataValidation;
 import org.apache.poi.ss.usermodel.DataValidationHelper;
+import org.apache.poi.ss.usermodel.FormulaEvaluator;
 import org.apache.poi.ss.usermodel.Row;
+import org.apache.poi.ss.usermodel.Sheet;
+import org.apache.poi.ss.usermodel.Workbook;
 import org.apache.poi.ss.usermodel.helpers.RowShifter;
 import org.apache.poi.ss.util.CellAddress;
 import org.apache.poi.ss.util.CellRangeAddress;
@@ -76,15 +82,15 @@
 import org.apache.poi.util.Beta;
 import org.apache.poi.util.Configurator;
 import org.apache.poi.util.Internal;
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
+
+import static java.lang.System.currentTimeMillis;
+import static org.apache.logging.log4j.util.Unbox.box;
 
 /**
  * High level representation of a worksheet.
  */
-public final class HSSFSheet implements org.apache.poi.ss.usermodel.Sheet {
-    private static final POILogger log = POILogFactory.getLogger(HSSFSheet.class);
-    private static final int DEBUG = POILogger.DEBUG;
+public final class HSSFSheet implements Sheet {
+    private static final Logger LOGGER = LogManager.getLogger(HSSFSheet.class);
 
     /**
      * width of 1px in columns with default width in units of 1/256 of a character width
@@ -122,7 +128,7 @@
      * scratch.  You should not be calling this from application code (its protected anyhow).
      *
      * @param workbook - The HSSF Workbook object associated with the sheet.
-     * @see org.apache.poi.hssf.usermodel.HSSFWorkbook#createSheet()
+     * @see HSSFWorkbook#createSheet()
      */
     protected HSSFSheet(HSSFWorkbook workbook) {
         _sheet = InternalSheet.createSheet();
@@ -137,7 +143,7 @@
      *
      * @param workbook - The HSSF Workbook object associated with the sheet.
      * @param sheet    - lowlevel Sheet object this sheet will represent
-     * @see org.apache.poi.hssf.usermodel.HSSFWorkbook#createSheet()
+     * @see HSSFWorkbook#createSheet()
      */
     protected HSSFSheet(HSSFWorkbook workbook, InternalSheet sheet) {
         this._sheet = sheet;
@@ -196,19 +202,16 @@
         }
 
         Iterator<CellValueRecordInterface> iter = sheet.getCellValueIterator();
-        long timestart = System.currentTimeMillis();
+        long timestart = currentTimeMillis();
 
-        if (log.check( POILogger.DEBUG )) {
-            log.log(DEBUG, "Time at start of cell creating in HSSF sheet = ",
-                    Long.valueOf(timestart));
-        }
+        LOGGER.atDebug().log("Time at start of cell creating in HSSF sheet = {}", box(timestart));
         HSSFRow lastrow = null;
 
         // Add every cell to its row
         while (iter.hasNext()) {
             CellValueRecordInterface cval = iter.next();
 
-            long cellstart = System.currentTimeMillis();
+            long cellstart = currentTimeMillis();
             HSSFRow hrow = lastrow;
 
             if (hrow == null || hrow.getRowNum() != cval.getRow()) {
@@ -229,24 +232,18 @@
                     hrow = createRowFromRecord(rowRec);
                 }
             }
-            if (log.check( POILogger.DEBUG )) {
+            LOGGER.atDebug().log(() -> {
                 if (cval instanceof Record) {
-                    log.log( DEBUG, "record id = ", Integer.toHexString( ( (org.apache.poi.hssf.record.Record) cval ).getSid() ) );
+                    return new SimpleMessage("record id = " + Integer.toHexString(((Record) cval).getSid()));
                 } else {
-                    log.log( DEBUG, "record = ", cval );
+                    return new SimpleMessage("record = " + cval);
                 }
-            }
+            });
             hrow.createCellFromRecord( cval );
-            if (log.check( POILogger.DEBUG )) {
-                log.log( DEBUG, "record took ",
-                    Long.valueOf( System.currentTimeMillis() - cellstart ) );
-            }
+            LOGGER.atDebug().log("record took {}ms", box(currentTimeMillis() - cellstart));
 
         }
-        if (log.check( POILogger.DEBUG )) {
-            log.log(DEBUG, "total sheet cell creation took ",
-                Long.valueOf(System.currentTimeMillis() - timestart));
-    }
+        LOGGER.atDebug().log("total sheet cell creation took {}ms", box(currentTimeMillis() - timestart));
     }
 
     /**
@@ -254,8 +251,8 @@
      *
      * @param rownum row number
      * @return High level HSSFRow object representing a row in the sheet
-     * @see org.apache.poi.hssf.usermodel.HSSFRow
-     * @see #removeRow(org.apache.poi.ss.usermodel.Row)
+     * @see HSSFRow
+     * @see #removeRow(Row)
      */
     @Override
     public HSSFRow createRow(int rownum) {
@@ -438,7 +435,7 @@
             private HSSFEvaluationWorkbook book = HSSFEvaluationWorkbook.create(getWorkbook());
 
             @Override
-            public void visitRecord(org.apache.poi.hssf.record.Record r) {
+            public void visitRecord(Record r) {
                 if (!(r instanceof DVRecord)) {
                     return;
                 }
@@ -815,17 +812,17 @@
      * Control if Excel should be asked to recalculate all formulas on this sheet
      * when the workbook is opened.<p>
      *
-     * Calculating the formula values with {@link org.apache.poi.ss.usermodel.FormulaEvaluator} is the
+     * Calculating the formula values with {@link FormulaEvaluator} is the
      * recommended solution, but this may be used for certain cases where
      * evaluation in POI is not possible.<p>
      *
      * It is recommended to force recalcuation of formulas on workbook level using
-     * {@link org.apache.poi.ss.usermodel.Workbook#setForceFormulaRecalculation(boolean)}
+     * {@link Workbook#setForceFormulaRecalculation(boolean)}
      * to ensure that all cross-worksheet formuals and external dependencies are updated.
      *
      * @param value true if the application will perform a full recalculation of
      *              this worksheet values when the workbook is opened
-     * @see org.apache.poi.ss.usermodel.Workbook#setForceFormulaRecalculation(boolean)
+     * @see Workbook#setForceFormulaRecalculation(boolean)
      */
     @Override
     public void setForceFormulaRecalculation(boolean value) {
@@ -1773,7 +1770,7 @@
         // add logic for hyperlinks etc, like in shiftRows()
     }
 
-    protected void insertChartRecords(List<org.apache.poi.hssf.record.Record> records) {
+    protected void insertChartRecords(List<Record> records) {
         int window2Loc = _sheet.findFirstRecordLocBySid(WindowTwoRecord.sid);
         _sheet.getRecords().addAll(window2Loc, records);
     }
diff --git a/src/java/org/apache/poi/hssf/usermodel/HSSFWorkbook.java b/src/java/org/apache/poi/hssf/usermodel/HSSFWorkbook.java
index 9d78e85..d6e5c63 100644
--- a/src/java/org/apache/poi/hssf/usermodel/HSSFWorkbook.java
+++ b/src/java/org/apache/poi/hssf/usermodel/HSSFWorkbook.java
@@ -17,12 +17,15 @@
 
 package org.apache.poi.hssf.usermodel;
 
+import static org.apache.logging.log4j.util.Unbox.box;
 import static org.apache.poi.hssf.model.InternalWorkbook.OLD_WORKBOOK_DIR_ENTRY_NAME;
 import static org.apache.poi.hssf.model.InternalWorkbook.WORKBOOK_DIR_ENTRY_NAMES;
 
+import java.io.BufferedOutputStream;
 import java.io.ByteArrayInputStream;
 import java.io.ByteArrayOutputStream;
 import java.io.File;
+import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
@@ -44,6 +47,8 @@
 import java.util.regex.Pattern;
 
 import org.apache.commons.codec.digest.DigestUtils;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.apache.poi.EncryptedDocumentException;
 import org.apache.poi.POIDocument;
 import org.apache.poi.ddf.EscherBSERecord;
@@ -70,6 +75,7 @@
 import org.apache.poi.hssf.record.ExtendedFormatRecord;
 import org.apache.poi.hssf.record.FilePassRecord;
 import org.apache.poi.hssf.record.FontRecord;
+import org.apache.poi.hssf.record.FormatRecord;
 import org.apache.poi.hssf.record.LabelRecord;
 import org.apache.poi.hssf.record.LabelSSTRecord;
 import org.apache.poi.hssf.record.NameRecord;
@@ -110,6 +116,7 @@
 import org.apache.poi.ss.usermodel.SheetVisibility;
 import org.apache.poi.ss.usermodel.Workbook;
 import org.apache.poi.ss.util.CellReference;
+import org.apache.poi.ss.util.WorkbookUtil;
 import org.apache.poi.util.Configurator;
 import org.apache.poi.util.HexDump;
 import org.apache.poi.util.IOUtils;
@@ -117,8 +124,6 @@
 import org.apache.poi.util.LittleEndian;
 import org.apache.poi.util.LittleEndianByteArrayInputStream;
 import org.apache.poi.util.LittleEndianByteArrayOutputStream;
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
 import org.apache.poi.util.Removal;
 
 /**
@@ -126,11 +131,11 @@
  * will construct whether they are reading or writing a workbook.  It is also the
  * top level object for creating new sheets/etc.
  *
- * @see org.apache.poi.hssf.model.InternalWorkbook
- * @see org.apache.poi.hssf.usermodel.HSSFSheet
+ * @see InternalWorkbook
+ * @see HSSFSheet
  */
 @SuppressWarnings("WeakerAccess")
-public final class HSSFWorkbook extends POIDocument implements org.apache.poi.ss.usermodel.Workbook {
+public final class HSSFWorkbook extends POIDocument implements Workbook {
 
     //arbitrarily selected; may need to increase
     private static final int MAX_RECORD_LENGTH = 100_000;
@@ -147,8 +152,6 @@
      */
     private static final int MAX_STYLES = 4030;
 
-    private static final int DEBUG = POILogger.DEBUG;
-
     /**
      * used for compile-time performance/memory optimization.  This determines the
      * initial capacity for the sheet collection.  Its currently set to 3.
@@ -203,7 +206,7 @@
      */
     private MissingCellPolicy missingCellPolicy = MissingCellPolicy.RETURN_NULL_AND_BLANK;
 
-    private static final POILogger log = POILogFactory.getLogger(HSSFWorkbook.class);
+    private static final Logger LOGGER = LogManager.getLogger(HSSFWorkbook.class);
 
     /**
      * The locator of user-defined functions.
@@ -237,7 +240,7 @@
      *
      * @throws IOException if the stream cannot be read
      * @see #HSSFWorkbook(POIFSFileSystem, boolean)
-     * @see org.apache.poi.poifs.filesystem.POIFSFileSystem
+     * @see POIFSFileSystem
      */
     public HSSFWorkbook(POIFSFileSystem fs) throws IOException {
         this(fs, true);
@@ -253,7 +256,7 @@
      *                      need to. If set, will store all of the POIFSFileSystem
      *                      in memory
      * @throws IOException if the stream cannot be read
-     * @see org.apache.poi.poifs.filesystem.POIFSFileSystem
+     * @see POIFSFileSystem
      */
     public HSSFWorkbook(POIFSFileSystem fs, boolean preserveNodes)
             throws IOException {
@@ -300,7 +303,7 @@
      *                      need to. If set, will store all of the POIFSFileSystem
      *                      in memory
      * @throws IOException if the stream cannot be read
-     * @see org.apache.poi.poifs.filesystem.POIFSFileSystem
+     * @see POIFSFileSystem
      */
     public HSSFWorkbook(DirectoryNode directory, POIFSFileSystem fs, boolean preserveNodes)
             throws IOException {
@@ -318,7 +321,7 @@
      *                      need to. If set, will store all of the POIFSFileSystem
      *                      in memory
      * @throws IOException if the stream cannot be read
-     * @see org.apache.poi.poifs.filesystem.POIFSFileSystem
+     * @see POIFSFileSystem
      */
     public HSSFWorkbook(DirectoryNode directory, boolean preserveNodes)
             throws IOException {
@@ -340,7 +343,7 @@
         //  it happens to be spelled.
         InputStream stream = directory.createDocumentInputStream(workbookName);
 
-        List<org.apache.poi.hssf.record.Record> records = RecordFactory.createRecords(stream);
+        List<Record> records = RecordFactory.createRecords(stream);
 
         workbook = InternalWorkbook.createWorkbook(records);
         setPropertiesFromWorkbook(workbook);
@@ -355,7 +358,7 @@
                 _sheets.add(new HSSFSheet(this, sheet));
             } catch (UnsupportedBOFType eb) {
                 // Hopefully there's a supported one after this!
-                log.log(POILogger.WARN, "Unsupported BOF found of type " + eb.getType());
+                LOGGER.atWarn().log("Unsupported BOF found of type {}", box(eb.getType()));
             }
         }
 
@@ -375,7 +378,7 @@
      * @throws IOException if the stream cannot be read
      * @see #HSSFWorkbook(InputStream, boolean)
      * @see #HSSFWorkbook(POIFSFileSystem)
-     * @see org.apache.poi.poifs.filesystem.POIFSFileSystem
+     * @see POIFSFileSystem
      */
     public HSSFWorkbook(InputStream s) throws IOException {
         this(s, true);
@@ -390,7 +393,7 @@
      *                      macros.  This takes more memory, so only say yes if you
      *                      need to.
      * @throws IOException if the stream cannot be read
-     * @see org.apache.poi.poifs.filesystem.POIFSFileSystem
+     * @see POIFSFileSystem
      * @see #HSSFWorkbook(POIFSFileSystem)
      */
     @SuppressWarnings("resource")   // POIFSFileSystem always closes the stream
@@ -421,13 +424,13 @@
      *
      * @param records a collection of sheet's records.
      * @param offset  the offset to search at
-     * @see org.apache.poi.hssf.record.LabelRecord
-     * @see org.apache.poi.hssf.record.LabelSSTRecord
-     * @see org.apache.poi.hssf.record.SSTRecord
+     * @see LabelRecord
+     * @see LabelSSTRecord
+     * @see SSTRecord
      */
 
-    private void convertLabelRecords(List<org.apache.poi.hssf.record.Record> records, int offset) {
-        log.log(POILogger.DEBUG, "convertLabelRecords called");
+    private void convertLabelRecords(List<Record> records, int offset) {
+        LOGGER.atDebug().log("convertLabelRecords called");
         for (int k = offset; k < records.size(); k++) {
             Record rec = records.get(k);
 
@@ -446,7 +449,7 @@
                 records.add(k, newrec);
             }
         }
-        log.log(POILogger.DEBUG, "convertLabelRecords exit");
+        LOGGER.atDebug().log("convertLabelRecords exit");
     }
 
     /**
@@ -655,7 +658,7 @@
      * allow you to show the data of one sheet when another is seen "selected"
      * in the tabs (at the bottom).
      *
-     * @see org.apache.poi.hssf.usermodel.HSSFSheet#setSelected(boolean)
+     * @see HSSFSheet#setSelected(boolean)
      */
     @Override
     public int getActiveSheetIndex() {
@@ -690,7 +693,7 @@
      * @throws IllegalArgumentException if the name is null or invalid
      *                                  or workbook already contains a sheet with this name
      * @see #createSheet(String)
-     * @see org.apache.poi.ss.util.WorkbookUtil#createSafeSheetName(String nameProposal)
+     * @see WorkbookUtil#createSafeSheetName(String nameProposal)
      */
     @Override
     public void setSheetName(int sheetIx, String name) {
@@ -770,7 +773,7 @@
      * @return index of the sheet (0 based). <tt>-1</tt> if not found
      */
     @Override
-    public int getSheetIndex(org.apache.poi.ss.usermodel.Sheet sheet) {
+    public int getSheetIndex(Sheet sheet) {
         return _sheets.indexOf(sheet);
     }
 
@@ -898,7 +901,7 @@
      * @return Sheet representing the new sheet.
      * @throws IllegalArgumentException if the name is null or invalid
      *                                  or workbook already contains a sheet with this name
-     * @see org.apache.poi.ss.util.WorkbookUtil#createSafeSheetName(String nameProposal)
+     * @see WorkbookUtil#createSafeSheetName(String nameProposal)
      */
     @Override
     public HSSFSheet createSheet(String sheetname) {
@@ -1328,7 +1331,7 @@
      *
      * @param newFile The new File you wish to write the XLS to
      * @throws IOException if anything can't be written.
-     * @see org.apache.poi.poifs.filesystem.POIFSFileSystem
+     * @see POIFSFileSystem
      */
     @Override
     public void write(File newFile) throws IOException {
@@ -1343,14 +1346,14 @@
      * a new POI POIFSFileSystem, passes in the workbook binary representation and
      * writes it out.
      * <p>
-     * If {@code stream} is a {@link java.io.FileOutputStream} on a networked drive
+     * If {@code stream} is a {@link FileOutputStream} on a networked drive
      * or has a high cost/latency associated with each written byte,
-     * consider wrapping the OutputStream in a {@link java.io.BufferedOutputStream}
+     * consider wrapping the OutputStream in a {@link BufferedOutputStream}
      * to improve write performance.
      *
      * @param stream - the java OutputStream you wish to write the XLS to
      * @throws IOException if anything can't be written.
-     * @see org.apache.poi.poifs.filesystem.POIFSFileSystem
+     * @see POIFSFileSystem
      */
     @Override
     public void write(OutputStream stream) throws IOException {
@@ -1405,7 +1408,7 @@
      */
     private static final class SheetRecordCollector implements RecordVisitor {
 
-        private List<org.apache.poi.hssf.record.Record> _list;
+        private List<Record> _list;
         private int _totalSize;
 
         public SheetRecordCollector() {
@@ -1418,7 +1421,7 @@
         }
 
         @Override
-        public void visitRecord(org.apache.poi.hssf.record.Record r) {
+        public void visitRecord(Record r) {
             _list.add(r);
             _totalSize += r.getRecordSize();
 
@@ -1426,7 +1429,7 @@
 
         public int serialize(int offset, byte[] data) {
             int result = 0;
-            for (org.apache.poi.hssf.record.Record rec : _list) {
+            for (Record rec : _list) {
                 result += rec.serialize(offset + result, data);
             }
             return result;
@@ -1442,9 +1445,7 @@
      * sheets, rows, cells, etc.
      */
     public byte[] getBytes() {
-        if (log.check(POILogger.DEBUG)) {
-            log.log(DEBUG, "HSSFWorkbook.getBytes()");
-        }
+        LOGGER.atDebug().log("HSSFWorkbook.getBytes()");
 
         HSSFSheet[] sheets = getSheets();
         int nSheets = sheets.length;
@@ -1744,8 +1745,8 @@
      * Returns the instance of HSSFDataFormat for this workbook.
      *
      * @return the HSSFDataFormat object
-     * @see org.apache.poi.hssf.record.FormatRecord
-     * @see org.apache.poi.hssf.record.Record
+     * @see FormatRecord
+     * @see Record
      */
     @Override
     public HSSFDataFormat createDataFormat() {
@@ -1929,7 +1930,7 @@
     public List<HSSFPictureData> getAllPictures() {
         // The drawing group record always exists at the top level, so we won't need to do this recursively.
         List<HSSFPictureData> pictures = new ArrayList<>();
-        for (org.apache.poi.hssf.record.Record r : workbook.getRecords()) {
+        for (Record r : workbook.getRecords()) {
             if (r instanceof AbstractEscherHolderRecord) {
                 ((AbstractEscherHolderRecord) r).decode();
                 List<EscherRecord> escherRecords = ((AbstractEscherHolderRecord) r).getEscherRecords();
diff --git a/src/java/org/apache/poi/hssf/usermodel/StaticFontMetrics.java b/src/java/org/apache/poi/hssf/usermodel/StaticFontMetrics.java
index a586c73..453f3db 100644
--- a/src/java/org/apache/poi/hssf/usermodel/StaticFontMetrics.java
+++ b/src/java/org/apache/poi/hssf/usermodel/StaticFontMetrics.java
@@ -26,8 +26,8 @@
 import java.util.Map;
 import java.util.Properties;
 
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 
 /**
  * Allows the user to lookup the font metrics for a particular font without
@@ -37,7 +37,7 @@
  * font. Use a multiplier for other sizes.
  */
 final class StaticFontMetrics {
-    private static final POILogger LOGGER = POILogFactory.getLogger(StaticFontMetrics.class);
+    private static final Logger LOGGER = LogManager.getLogger(StaticFontMetrics.class);
 	/** The font metrics property file we're using */
 	private static Properties fontMetricsProps;
 	/** Our cache of font details we've already looked up */
@@ -109,12 +109,12 @@
             if (propFileName != null) {
                 propFile = new File(propFileName);
                 if (!propFile.exists()) {
-                    LOGGER.log(POILogger.WARN, "font_metrics.properties not found at path "+propFile.getAbsolutePath());
+					LOGGER.atWarn().log("font_metrics.properties not found at path {}", propFile.getAbsolutePath());
                     propFile = null;
                 }
             }
         } catch (SecurityException e) {
-            LOGGER.log(POILogger.WARN, "Can't access font.metrics.filename system property", e);
+            LOGGER.atWarn().withThrowable(e).log("Can't access font.metrics.filename system property");
         }
 
         try (InputStream metricsIn = (propFile != null)
diff --git a/src/java/org/apache/poi/hssf/usermodel/helpers/HSSFColumnShifter.java b/src/java/org/apache/poi/hssf/usermodel/helpers/HSSFColumnShifter.java
index 5ed4870..3f86cad 100644
--- a/src/java/org/apache/poi/hssf/usermodel/helpers/HSSFColumnShifter.java
+++ b/src/java/org/apache/poi/hssf/usermodel/helpers/HSSFColumnShifter.java
@@ -17,14 +17,14 @@
 
 package org.apache.poi.hssf.usermodel.helpers;
 
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.apache.poi.hssf.usermodel.HSSFSheet;
 import org.apache.poi.ss.formula.FormulaShifter;
 import org.apache.poi.ss.formula.eval.NotImplementedException;
 import org.apache.poi.ss.usermodel.helpers.ColumnShifter;
 import org.apache.poi.util.Beta;
 import org.apache.poi.util.NotImplemented;
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
 
 /**
  * Helper for shifting columns up or down
@@ -35,7 +35,7 @@
 // {@link org.apache.poi.xssf.usermodel.helpers.XSSFColumnShifter}
 @Beta
 public final class HSSFColumnShifter extends ColumnShifter {
-    private static final POILogger LOG = POILogFactory.getLogger(HSSFColumnShifter.class);
+    private static final Logger LOG = LogManager.getLogger(HSSFColumnShifter.class);
 
     public HSSFColumnShifter(HSSFSheet sh) {
         super(sh);
diff --git a/src/java/org/apache/poi/hssf/usermodel/helpers/HSSFRowShifter.java b/src/java/org/apache/poi/hssf/usermodel/helpers/HSSFRowShifter.java
index 8889205..4a74355 100644
--- a/src/java/org/apache/poi/hssf/usermodel/helpers/HSSFRowShifter.java
+++ b/src/java/org/apache/poi/hssf/usermodel/helpers/HSSFRowShifter.java
@@ -17,15 +17,13 @@
 
 package org.apache.poi.hssf.usermodel.helpers;
 
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.apache.poi.hssf.usermodel.HSSFSheet;
 import org.apache.poi.ss.formula.FormulaShifter;
 import org.apache.poi.ss.formula.eval.NotImplementedException;
-import org.apache.poi.ss.usermodel.Row;
-import org.apache.poi.ss.usermodel.Sheet;
 import org.apache.poi.ss.usermodel.helpers.RowShifter;
 import org.apache.poi.util.NotImplemented;
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
 
 /**
  * Helper for shifting rows up or down
@@ -33,7 +31,7 @@
 // non-Javadoc: When possible, code should be implemented in the RowShifter abstract class to avoid duplication with
 // {@link org.apache.poi.xssf.usermodel.helpers.XSSFRowShifter}
 public final class HSSFRowShifter extends RowShifter {
-    private static final POILogger LOG = POILogFactory.getLogger(HSSFRowShifter.class);
+    private static final Logger LOG = LogManager.getLogger(HSSFRowShifter.class);
 
     public HSSFRowShifter(HSSFSheet sh) {
         super(sh);
diff --git a/src/java/org/apache/poi/poifs/crypt/ChunkedCipherOutputStream.java b/src/java/org/apache/poi/poifs/crypt/ChunkedCipherOutputStream.java
index d5ea57a..5270fc0 100644
--- a/src/java/org/apache/poi/poifs/crypt/ChunkedCipherOutputStream.java
+++ b/src/java/org/apache/poi/poifs/crypt/ChunkedCipherOutputStream.java
@@ -32,6 +32,8 @@
 import javax.crypto.ShortBufferException;
 
 import com.zaxxer.sparsebits.SparseBitSet;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.apache.poi.EncryptedDocumentException;
 import org.apache.poi.poifs.filesystem.DirectoryNode;
 import org.apache.poi.poifs.filesystem.POIFSWriterEvent;
@@ -40,13 +42,11 @@
 import org.apache.poi.util.Internal;
 import org.apache.poi.util.LittleEndian;
 import org.apache.poi.util.LittleEndianConsts;
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
 import org.apache.poi.util.TempFile;
 
 @Internal
 public abstract class ChunkedCipherOutputStream extends FilterOutputStream {
-    private static final POILogger LOG = POILogFactory.getLogger(ChunkedCipherOutputStream.class);
+    private static final Logger LOG = LogManager.getLogger(ChunkedCipherOutputStream.class);
     //arbitrarily selected; may need to increase
     private static final int MAX_RECORD_LENGTH = 100_000;
 
@@ -257,7 +257,7 @@
     @Override
     public void close() throws IOException {
         if (isClosed) {
-            LOG.log(POILogger.DEBUG, "ChunkedCipherOutputStream was already closed - ignoring");
+            LOG.atDebug().log("ChunkedCipherOutputStream was already closed - ignoring");
             return;
         }
 
@@ -324,7 +324,7 @@
                 }
 
                 if (!fileOut.delete()) {
-                    LOG.log(POILogger.ERROR, "Can't delete temporary encryption file: ", fileOut);
+                    LOG.atError().log("Can't delete temporary encryption file: {}", fileOut);
                 }
             } catch (IOException e) {
                 throw new EncryptedDocumentException(e);
diff --git a/src/java/org/apache/poi/poifs/crypt/standard/StandardEncryptor.java b/src/java/org/apache/poi/poifs/crypt/standard/StandardEncryptor.java
index 84c8970..097a7bd 100644
--- a/src/java/org/apache/poi/poifs/crypt/standard/StandardEncryptor.java
+++ b/src/java/org/apache/poi/poifs/crypt/standard/StandardEncryptor.java
@@ -36,6 +36,8 @@
 import javax.crypto.CipherOutputStream;
 import javax.crypto.SecretKey;
 
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.apache.poi.EncryptedDocumentException;
 import org.apache.poi.poifs.crypt.CryptoFunctions;
 import org.apache.poi.poifs.crypt.DataSpaceMapUtils;
@@ -49,12 +51,10 @@
 import org.apache.poi.util.LittleEndianByteArrayOutputStream;
 import org.apache.poi.util.LittleEndianConsts;
 import org.apache.poi.util.LittleEndianOutputStream;
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
 import org.apache.poi.util.TempFile;
 
 public class StandardEncryptor extends Encryptor {
-    private static final POILogger LOG = POILogFactory.getLogger(StandardEncryptor.class);
+    private static final Logger LOG = LogManager.getLogger(StandardEncryptor.class);
 
     protected StandardEncryptor() {}
 
@@ -193,7 +193,7 @@
                     IOUtils.copy(fis, leos);
                 }
                 if (!fileOut.delete()) {
-                    LOG.log(POILogger.ERROR, "Can't delete temporary encryption file: ", fileOut);
+                    LOG.atError().log("Can't delete temporary encryption file: {}", fileOut);
                 }
 
                 leos.close();
diff --git a/src/java/org/apache/poi/poifs/filesystem/POIFSDocumentPath.java b/src/java/org/apache/poi/poifs/filesystem/POIFSDocumentPath.java
index c613bdc..1db851e 100644
--- a/src/java/org/apache/poi/poifs/filesystem/POIFSDocumentPath.java
+++ b/src/java/org/apache/poi/poifs/filesystem/POIFSDocumentPath.java
@@ -25,8 +25,8 @@
 import java.util.function.Predicate;
 import java.util.stream.Stream;
 
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 
 /**
  * Class POIFSDocumentPath
@@ -34,7 +34,7 @@
 
 public class POIFSDocumentPath {
 
-    private static final POILogger log = POILogFactory.getLogger(POIFSDocumentPath.class);
+    private static final Logger LOGGER = LogManager.getLogger(POIFSDocumentPath.class);
 
     private final String[] components;
     private int hashcode; //lazy-compute hashCode
diff --git a/src/java/org/apache/poi/poifs/filesystem/POIFSFileSystem.java b/src/java/org/apache/poi/poifs/filesystem/POIFSFileSystem.java
index 94c68a6..2fb09dc 100644
--- a/src/java/org/apache/poi/poifs/filesystem/POIFSFileSystem.java
+++ b/src/java/org/apache/poi/poifs/filesystem/POIFSFileSystem.java
@@ -34,6 +34,8 @@
 import java.util.List;
 
 import org.apache.commons.math3.util.ArithmeticUtils;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.apache.poi.EmptyFileException;
 import org.apache.poi.poifs.common.POIFSBigBlockSize;
 import org.apache.poi.poifs.common.POIFSConstants;
@@ -49,8 +51,6 @@
 import org.apache.poi.poifs.storage.HeaderBlock;
 import org.apache.poi.util.IOUtils;
 import org.apache.poi.util.Internal;
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
 
 /**
  * <p>This is the main class of the POIFS system; it manages the entire
@@ -63,7 +63,7 @@
     //arbitrarily selected; may need to increase
     private static final int MAX_RECORD_LENGTH = 100_000;
 
-    private static final POILogger LOG = POILogFactory.getLogger(POIFSFileSystem.class);
+    private static final Logger LOG = LogManager.getLogger(POIFSFileSystem.class);
 
     /**
      * Maximum number size (in blocks) of the allocation table as supported by
@@ -327,7 +327,7 @@
             }
             // else not success? Try block did not complete normally
             // just print stack trace and leave original ex to be thrown
-            LOG.log(POILogger.ERROR, "can't close input stream", e);
+            LOG.atError().withThrowable(e).log("can't close input stream");
         }
     }
 
diff --git a/src/java/org/apache/poi/poifs/macros/VBAMacroReader.java b/src/java/org/apache/poi/poifs/macros/VBAMacroReader.java
index 624a5fd..2f28c63 100644
--- a/src/java/org/apache/poi/poifs/macros/VBAMacroReader.java
+++ b/src/java/org/apache/poi/poifs/macros/VBAMacroReader.java
@@ -17,6 +17,7 @@
 
 package org.apache.poi.poifs.macros;
 
+import static org.apache.logging.log4j.util.Unbox.box;
 import static org.apache.poi.util.StringUtil.endsWithIgnoreCase;
 import static org.apache.poi.util.StringUtil.startsWithIgnoreCase;
 
@@ -37,6 +38,8 @@
 import java.util.zip.ZipEntry;
 import java.util.zip.ZipInputStream;
 
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.apache.poi.poifs.filesystem.DirectoryNode;
 import org.apache.poi.poifs.filesystem.DocumentInputStream;
 import org.apache.poi.poifs.filesystem.DocumentNode;
@@ -49,8 +52,6 @@
 import org.apache.poi.util.HexDump;
 import org.apache.poi.util.IOUtils;
 import org.apache.poi.util.LittleEndian;
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
 import org.apache.poi.util.RLEDecompressingInputStream;
 import org.apache.poi.util.StringUtil;
 
@@ -68,7 +69,7 @@
  * @since 3.15-beta2
  */
 public class VBAMacroReader implements Closeable {
-    private static final POILogger LOGGER = POILogFactory.getLogger(VBAMacroReader.class);
+    private static final Logger LOGGER = LogManager.getLogger(VBAMacroReader.class);
 
     //arbitrary limit on size of strings to read, etc.
     private static final int MAX_STRING_LENGTH = 20000;
@@ -663,9 +664,7 @@
             }
 
         }
-        if (records >= maxNameRecords) {
-            LOGGER.log(POILogger.WARN, "Hit max name records to read ("+maxNameRecords+"). Stopped early.");
-        }
+        LOGGER.atWarn().log("Hit max name records to read (" + maxNameRecords + "). Stopped early.");
     }
 
     private static String readUnicode(InputStream is, int maxLength) throws IOException {
@@ -684,7 +683,7 @@
             read += 2;
         }
         if (read >= maxLength) {
-            LOGGER.log(POILogger.WARN, "stopped reading unicode name after "+read+" bytes");
+            LOGGER.atWarn().log("stopped reading unicode name after {} bytes", box(read));
         }
         return new String (bos.toByteArray(), StandardCharsets.UTF_16LE);
     }
@@ -747,21 +746,21 @@
                     if (module != null) {
                         module.moduleType = ModuleType.Document;
                     } else {
-                        LOGGER.log(POILogger.WARN, "couldn't find module with name: "+mn);
+                        LOGGER.atWarn().log("couldn't find module with name: {}", mn);
                     }
                 } else if ("Module".equals(tokens[0]) && tokens.length > 1) {
                     ModuleImpl module = getModule(tokens[1], moduleNameMap, modules);
                     if (module != null) {
                         module.moduleType = ModuleType.Module;
                     } else {
-                        LOGGER.log(POILogger.WARN, "couldn't find module with name: "+tokens[1]);
+                        LOGGER.atWarn().log("couldn't find module with name: {}", tokens[1]);
                     }
                 } else if ("Class".equals(tokens[0]) && tokens.length > 1) {
                     ModuleImpl module = getModule(tokens[1], moduleNameMap, modules);
                     if (module != null) {
                         module.moduleType = ModuleType.Class;
                     } else {
-                        LOGGER.log(POILogger.WARN, "couldn't find module with name: "+tokens[1]);
+                        LOGGER.atWarn().log("couldn't find module with name: {}", tokens[1]);
                     }
                 }
             }
diff --git a/src/java/org/apache/poi/poifs/nio/FileBackedDataSource.java b/src/java/org/apache/poi/poifs/nio/FileBackedDataSource.java
index d74eb9d..e3001f2 100644
--- a/src/java/org/apache/poi/poifs/nio/FileBackedDataSource.java
+++ b/src/java/org/apache/poi/poifs/nio/FileBackedDataSource.java
@@ -29,15 +29,15 @@
 import java.nio.channels.WritableByteChannel;
 import java.util.IdentityHashMap;
 
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.apache.poi.util.IOUtils;
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
 
 /**
  * A POIFS {@link DataSource} backed by a File
  */
 public class FileBackedDataSource extends DataSource implements Closeable {
-    private static final POILogger LOG = POILogFactory.getLogger(FileBackedDataSource.class);
+    private static final Logger LOG = LogManager.getLogger(FileBackedDataSource.class);
 
     private final FileChannel channel;
     private Long channelSize;
@@ -195,10 +195,10 @@
             try {
                 CleanerUtil.getCleaner().freeBuffer(buffer);
             } catch (IOException e) {
-                LOG.log(POILogger.WARN, "Failed to unmap the buffer", e);
+                LOG.atWarn().withThrowable(e).log("Failed to unmap the buffer");
             }
         } else {
-            LOG.log(POILogger.DEBUG, CleanerUtil.UNMAP_NOT_SUPPORTED_REASON);
+            LOG.atDebug().log(CleanerUtil.UNMAP_NOT_SUPPORTED_REASON);
         }
     }
 }
diff --git a/src/java/org/apache/poi/poifs/property/PropertyTable.java b/src/java/org/apache/poi/poifs/property/PropertyTable.java
index e1f663c..596bea5 100644
--- a/src/java/org/apache/poi/poifs/property/PropertyTable.java
+++ b/src/java/org/apache/poi/poifs/property/PropertyTable.java
@@ -24,6 +24,8 @@
 import java.util.List;
 import java.util.Stack;
 
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.apache.poi.poifs.common.POIFSBigBlockSize;
 import org.apache.poi.poifs.common.POIFSConstants;
 import org.apache.poi.poifs.filesystem.BATManaged;
@@ -31,8 +33,8 @@
 import org.apache.poi.poifs.filesystem.POIFSStream;
 import org.apache.poi.poifs.storage.HeaderBlock;
 import org.apache.poi.util.IOUtils;
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
+
+import static org.apache.logging.log4j.util.Unbox.box;
 
 /**
  * This class embodies the Property Table for a {@link POIFSFileSystem};
@@ -41,7 +43,7 @@
  * chain of blocks.
  */
 public final class PropertyTable implements BATManaged {
-    private static final POILogger LOG = POILogFactory.getLogger(PropertyTable.class);
+    private static final Logger LOG = LogManager.getLogger(PropertyTable.class);
 
     //arbitrarily selected; may need to increase
     private static final int MAX_RECORD_LENGTH = 100_000;
@@ -96,8 +98,7 @@
                     // Looks to be a truncated block
                     // This isn't allowed, but some third party created files
                     //  sometimes do this, and we can normally read anyway
-                    LOG.log(POILogger.WARN, "Short Property Block, ", bb.remaining(),
-                            " bytes instead of the expected " + _bigBigBlockSize.getBigBlockSize());
+                    LOG.atWarn().log("Short Property Block, {} bytes instead of the expected {}", box(bb.remaining()),box(_bigBigBlockSize.getBigBlockSize()));
                     toRead = bb.remaining();
                 }
 
@@ -247,8 +248,7 @@
         if (! Property.isValidIndex(index))
             return false;
         if (index < 0 || index >= _properties.size()) {
-            LOG.log(POILogger.WARN, "Property index " + index +
-                    "outside the valid range 0.."+_properties.size());
+            LOG.atWarn().log("Property index {} outside the valid range 0..{}", box(index),box(_properties.size()));
             return false;
         }
         return true;
diff --git a/src/java/org/apache/poi/sl/draw/BitmapImageRenderer.java b/src/java/org/apache/poi/sl/draw/BitmapImageRenderer.java
index 2113971..96e63a6 100644
--- a/src/java/org/apache/poi/sl/draw/BitmapImageRenderer.java
+++ b/src/java/org/apache/poi/sl/draw/BitmapImageRenderer.java
@@ -40,16 +40,16 @@
 import javax.imageio.stream.ImageInputStream;
 import javax.imageio.stream.MemoryCacheImageInputStream;
 
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.apache.poi.sl.usermodel.PictureData.PictureType;
 import org.apache.poi.util.IOUtils;
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
 
 /**
  * For now this class renders only images supported by the javax.imageio.ImageIO framework.
  **/
 public class BitmapImageRenderer implements ImageRenderer {
-    private static final POILogger LOG = POILogFactory.getLogger(BitmapImageRenderer.class);
+    private static final Logger LOG = LogManager.getLogger(BitmapImageRenderer.class);
 
     protected BufferedImage img;
 
@@ -200,7 +200,7 @@
                 // multiple locations above ...
                 throw lastException;
             }
-            LOG.log(POILogger.WARN, "Content-type: "+contentType+" is not support. Image ignored.");
+            LOG.atWarn().log("Content-type: {} is not support. Image ignored.", contentType);
             return null;
         }
 
diff --git a/src/java/org/apache/poi/sl/draw/DrawPaint.java b/src/java/org/apache/poi/sl/draw/DrawPaint.java
index 157c410..e78dd2e 100644
--- a/src/java/org/apache/poi/sl/draw/DrawPaint.java
+++ b/src/java/org/apache/poi/sl/draw/DrawPaint.java
@@ -46,6 +46,8 @@
 import java.util.function.BiFunction;
 import java.util.stream.Stream;
 
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.apache.poi.sl.usermodel.AbstractColorStyle;
 import org.apache.poi.sl.usermodel.ColorStyle;
 import org.apache.poi.sl.usermodel.Insets2D;
@@ -57,8 +59,6 @@
 import org.apache.poi.sl.usermodel.PaintStyle.TexturePaint;
 import org.apache.poi.sl.usermodel.PlaceableShape;
 import org.apache.poi.util.Dimension2DDouble;
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
 
 
 /**
@@ -69,7 +69,9 @@
 public class DrawPaint {
     // HSL code is public domain - see https://tips4java.wordpress.com/contact-us/
 
-    private static final POILogger LOG = POILogFactory.getLogger(DrawPaint.class);
+    // HSL code is public domain - see https://tips4java.wordpress.com/contact-us/
+
+    private static final Logger LOG = LogManager.getLogger(DrawPaint.class);
 
     private static final Color TRANSPARENT = new Color(1f,1f,1f,0f);
 
@@ -286,7 +288,7 @@
 
             BufferedImage image = renderer.getImage(imgDim);
             if(image == null) {
-                LOG.log(POILogger.ERROR, "Can't load image data");
+                LOG.atError().log("Can't load image data");
                 return TRANSPARENT;
             }
 
@@ -336,7 +338,7 @@
             // TODO: check why original bitmaps scale/behave differently to vector based images
             return new DrawTexturePaint(image, s, fill, flipX, flipY, renderer instanceof BitmapImageRenderer);
         } catch (IOException e) {
-            LOG.log(POILogger.ERROR, "Can't load image data - using transparent color", e);
+            LOG.atError().withThrowable(e).log("Can't load image data - using transparent color");
             return TRANSPARENT;
         }
     }
@@ -796,10 +798,10 @@
         try {
             graphics.fill(shape);
         } catch (ArrayIndexOutOfBoundsException e) {
-            LOG.log(POILogger.WARN, "IBM JDK failed with TexturePaintContext AIOOBE - try adding the following to the VM parameter:\n" +
+            LOG.atWarn().withThrowable(e).log("IBM JDK failed with TexturePaintContext AIOOBE - try adding the following to the VM parameter:\n" +
                 "-Xjit:exclude={sun/java2d/pipe/AlphaPaintPipe.renderPathTile(Ljava/lang/Object;[BIIIIII)V} and " +
                 "search for 'JIT Problem Determination for IBM SDK using -Xjit' (http://www-01.ibm.com/support/docview.wss?uid=swg21294023) " +
-                "for how to add/determine further excludes", e);
+                "for how to add/determine further excludes");
         }
     }
 }
diff --git a/src/java/org/apache/poi/sl/draw/DrawPictureShape.java b/src/java/org/apache/poi/sl/draw/DrawPictureShape.java
index 9332116..71cb1bd 100644
--- a/src/java/org/apache/poi/sl/draw/DrawPictureShape.java
+++ b/src/java/org/apache/poi/sl/draw/DrawPictureShape.java
@@ -27,17 +27,17 @@
 import java.util.function.Supplier;
 import java.util.stream.StreamSupport;
 
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.apache.poi.common.usermodel.PictureType;
 import org.apache.poi.poifs.filesystem.FileMagic;
 import org.apache.poi.sl.usermodel.PictureData;
 import org.apache.poi.sl.usermodel.PictureShape;
 import org.apache.poi.sl.usermodel.RectAlign;
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
 
 
 public class DrawPictureShape extends DrawSimpleShape {
-    private static final POILogger LOG = POILogFactory.getLogger(DrawPictureShape.class);
+    private static final Logger LOG = LogManager.getLogger(DrawPictureShape.class);
 
     public DrawPictureShape(PictureShape<?,?> shape) {
         super(shape);
@@ -69,7 +69,7 @@
                     return;
                 }
             } catch (IOException e) {
-                LOG.log(POILogger.ERROR, "image can't be loaded/rendered.", e);
+                LOG.atError().withThrowable(e).log("image can't be loaded/rendered.");
             }
         }
     }
@@ -93,8 +93,8 @@
 
         // the fallback is the BitmapImageRenderer, at least it gracefully handles invalid images
         final Supplier<ImageRenderer> getFallback = () -> {
-            LOG.log(POILogger.WARN, "No suitable image renderer found for content-type '",
-                contentType, "' - include poi-scratchpad (for wmf/emf) or poi-ooxml (for svg) jars!");
+            LOG.atWarn().log("No suitable image renderer found for content-type '{}' - include " +
+                    "poi-scratchpad (for wmf/emf) or poi-ooxml (for svg) jars!", contentType);
             return fallback;
         };
 
diff --git a/src/java/org/apache/poi/sl/draw/DrawTextParagraph.java b/src/java/org/apache/poi/sl/draw/DrawTextParagraph.java
index e047b34..b49f727 100644
--- a/src/java/org/apache/poi/sl/draw/DrawTextParagraph.java
+++ b/src/java/org/apache/poi/sl/draw/DrawTextParagraph.java
@@ -37,6 +37,8 @@
 import java.util.Locale;
 import java.util.Map;
 
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.apache.poi.common.usermodel.fonts.FontGroup;
 import org.apache.poi.common.usermodel.fonts.FontGroup.FontGroupRange;
 import org.apache.poi.common.usermodel.fonts.FontInfo;
@@ -57,12 +59,12 @@
 import org.apache.poi.sl.usermodel.TextShape.TextDirection;
 import org.apache.poi.util.Internal;
 import org.apache.poi.util.LocaleUtil;
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
 import org.apache.poi.util.Units;
 
+import static org.apache.logging.log4j.util.Unbox.box;
+
 public class DrawTextParagraph implements Drawable {
-    private static final POILogger LOG = POILogFactory.getLogger(DrawTextParagraph.class);
+    private static final Logger LOG = LogManager.getLogger(DrawTextParagraph.class);
 
     /** Keys for passing hyperlinks to the graphics context */
     public static final XlinkAttribute HYPERLINK_HREF = new XlinkAttribute("href");
@@ -713,10 +715,12 @@
 
                 if (partBegin < partEnd) {
                     // handle (b) and (c)
-                    attList.add(new AttributedStringData(TextAttribute.FAMILY, fontMapped.getFontName(Locale.ROOT), beginIndex+partBegin, beginIndex+partEnd));
-                    if (LOG.check(POILogger.DEBUG)) {
-                        LOG.log(POILogger.DEBUG, "mapped: ",fontMapped.getFontName(Locale.ROOT)," ",(beginIndex+partBegin)," ",(beginIndex+partEnd)," - ",runText.substring(partBegin, partEnd));
-                    }
+
+                    final String fontName = fontMapped.getFontName(Locale.ROOT);
+                    final int startIndex = beginIndex + partBegin;
+                    final int endIndex = beginIndex + partEnd;
+                    attList.add(new AttributedStringData(TextAttribute.FAMILY, fontName, startIndex, endIndex));
+                    LOG.atDebug().log("mapped: {} {} {} - {}", fontName, box(startIndex),box(endIndex),runText.substring(partBegin, partEnd));
                 }
 
                 // fallback for unsupported glyphs
@@ -725,10 +729,11 @@
 
                 if (partBegin < partEnd) {
                     // handle (a) and (b)
-                    attList.add(new AttributedStringData(TextAttribute.FAMILY, fontFallback.getFontName(Locale.ROOT), beginIndex+partBegin, beginIndex+partEnd));
-                    if (LOG.check(POILogger.DEBUG)) {
-                        LOG.log(POILogger.DEBUG, "fallback: ",fontFallback.getFontName(Locale.ROOT)," ",(beginIndex+partBegin)," ",(beginIndex+partEnd)," - ",runText.substring(partBegin, partEnd));
-                    }
+                    final String fontName = fontFallback.getFontName(Locale.ROOT);
+                    final int startIndex = beginIndex + partBegin;
+                    final int endIndex = beginIndex + partEnd;
+                    attList.add(new AttributedStringData(TextAttribute.FAMILY, fontName, startIndex, endIndex));
+                    LOG.atDebug().log("fallback: {} {} {} - {}", fontName, box(startIndex),box(endIndex),runText.substring(partBegin, partEnd));
                 }
             }
 
diff --git a/src/java/org/apache/poi/sl/draw/SLGraphics.java b/src/java/org/apache/poi/sl/draw/SLGraphics.java
index dfd7444..9d0398e 100644
--- a/src/java/org/apache/poi/sl/draw/SLGraphics.java
+++ b/src/java/org/apache/poi/sl/draw/SLGraphics.java
@@ -18,22 +18,7 @@
 package org.apache.poi.sl.draw;
 
 
-import java.awt.BasicStroke;
-import java.awt.Color;
-import java.awt.Composite;
-import java.awt.Font;
-import java.awt.FontMetrics;
-import java.awt.Graphics;
-import java.awt.Graphics2D;
-import java.awt.GraphicsConfiguration;
-import java.awt.GraphicsEnvironment;
-import java.awt.Image;
-import java.awt.Paint;
-import java.awt.Rectangle;
-import java.awt.RenderingHints;
-import java.awt.Shape;
-import java.awt.Stroke;
-import java.awt.Toolkit;
+import java.awt.*;
 import java.awt.font.FontRenderContext;
 import java.awt.font.GlyphVector;
 import java.awt.font.TextLayout;
@@ -52,6 +37,8 @@
 import java.text.AttributedCharacterIterator;
 import java.util.Map;
 
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.apache.poi.sl.usermodel.FreeformShape;
 import org.apache.poi.sl.usermodel.GroupShape;
 import org.apache.poi.sl.usermodel.Insets2D;
@@ -61,8 +48,6 @@
 import org.apache.poi.sl.usermodel.TextRun;
 import org.apache.poi.sl.usermodel.VerticalAlignment;
 import org.apache.poi.util.NotImplemented;
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
 import org.apache.poi.util.SuppressForbidden;
 
 /**
@@ -70,7 +55,7 @@
  */
 public class SLGraphics extends Graphics2D implements Cloneable {
 
-    private static final POILogger LOG = POILogFactory.getLogger(SLGraphics.class);
+    private static final Logger LOG = LogManager.getLogger(SLGraphics.class);
 
     //The ppt object to write into.
     private GroupShape<?,?> _group;
@@ -110,8 +95,8 @@
     /**
      * Gets the current font.
      * @return    this graphics context's current font.
-     * @see       java.awt.Font
-     * @see       java.awt.Graphics#setFont(Font)
+     * @see       Font
+     * @see       Graphics#setFont(Font)
      */
     public Font getFont(){
         return _font;
@@ -122,10 +107,10 @@
      * All subsequent text operations using this graphics context
      * use this font.
      * @param  font   the font.
-     * @see     java.awt.Graphics#getFont
-     * @see     java.awt.Graphics#drawString(java.lang.String, int, int)
-     * @see     java.awt.Graphics#drawBytes(byte[], int, int, int, int)
-     * @see     java.awt.Graphics#drawChars(char[], int, int, int, int)
+     * @see     Graphics#getFont
+     * @see     Graphics#drawString(String, int, int)
+     * @see     Graphics#drawBytes(byte[], int, int, int, int)
+     * @see     Graphics#drawChars(char[], int, int, int, int)
     */
     public void setFont(Font font){
         this._font = font;
@@ -134,8 +119,8 @@
     /**
      * Gets this graphics context's current color.
      * @return    this graphics context's current color.
-     * @see       java.awt.Color
-     * @see       java.awt.Graphics#setColor
+     * @see       Color
+     * @see       Graphics#setColor
      */
      public Color getColor(){
         return _foreground;
@@ -146,8 +131,8 @@
      * color. All subsequent graphics operations using this graphics
      * context use this specified color.
      * @param     c   the new rendering color.
-     * @see       java.awt.Color
-     * @see       java.awt.Graphics#getColor
+     * @see       Color
+     * @see       Graphics#getColor
      */
     public void setColor(Color c) {
         setPaint(c);
@@ -179,7 +164,7 @@
      * @return the current <code>Graphics2D</code> <code>Paint</code>,
      * which defines a color or pattern.
      * @see #setPaint
-     * @see java.awt.Graphics#setColor
+     * @see Graphics#setColor
      */
     public Paint getPaint(){
         return _paint;
@@ -193,7 +178,7 @@
      * of this <code>Graphics2D</code>.
      * @param paint the <code>Paint</code> object to be used to generate
      * color during the rendering process, or <code>null</code>
-     * @see java.awt.Graphics#setColor
+     * @see Graphics#setColor
      */
      public void setPaint(Paint paint){
         if(paint == null) return;
@@ -235,7 +220,7 @@
      * @param shape the <code>Shape</code> to be rendered
      * @see #setStroke
      * @see #setPaint
-     * @see java.awt.Graphics#setColor
+     * @see Graphics#setColor
      * @see #_transform
      * @see #setTransform
      * @see #clip
@@ -272,8 +257,8 @@
      * @throws NullPointerException if <code>str</code> is
      *         <code>null</code>
      * @see #setPaint
-     * @see java.awt.Graphics#setColor
-     * @see java.awt.Graphics#setFont
+     * @see Graphics#setColor
+     * @see Graphics#setFont
      * @see #setTransform
      * @see #setComposite
      * @see #setClip
@@ -332,7 +317,7 @@
      * <code>Paint</code>, and <code>Composite</code>.
      * @param shape the <code>Shape</code> to be filled
      * @see #setPaint
-     * @see java.awt.Graphics#setColor
+     * @see Graphics#setColor
      * @see #_transform
      * @see #setTransform
      * @see #setComposite
@@ -374,7 +359,7 @@
      * The <i>user clip</i> modified by this method is independent of the
      * clipping associated with device bounds and visibility.  If no clip has
      * previously been set, or if the clip has been cleared using
-     * {@link java.awt.Graphics#setClip(Shape) setClip} with a
+     * {@link Graphics#setClip(Shape) setClip} with a
      * <code>null</code> argument, the specified <code>Shape</code> becomes
      * the new user clip.
      * @param s the <code>Shape</code> to be intersected with the current
@@ -396,10 +381,10 @@
      * @return      a <code>Shape</code> object representing the
      *              current clipping area, or <code>null</code> if
      *              no clip is set.
-     * @see         java.awt.Graphics#getClipBounds()
-     * @see         java.awt.Graphics#clipRect
-     * @see         java.awt.Graphics#setClip(int, int, int, int)
-     * @see         java.awt.Graphics#setClip(Shape)
+     * @see         Graphics#getClipBounds()
+     * @see         Graphics#clipRect
+     * @see         Graphics#setClip(int, int, int, int)
+     * @see         Graphics#setClip(Shape)
      * @since       JDK1.1
      */
     @NotImplemented
@@ -445,7 +430,7 @@
      *                    at the four corners.
      * @param      arcHeight the vertical diameter of the arc
      *                    at the four corners.
-     * @see        java.awt.Graphics#fillRoundRect
+     * @see        Graphics#fillRoundRect
      */
     public void drawRoundRect(int x, int y, int width, int height,
                               int arcWidth, int arcHeight){
@@ -461,8 +446,8 @@
      * @param       str      the string to be drawn.
      * @param       x        the <i>x</i> coordinate.
      * @param       y        the <i>y</i> coordinate.
-     * @see         java.awt.Graphics#drawBytes
-     * @see         java.awt.Graphics#drawChars
+     * @see         Graphics#drawBytes
+     * @see         Graphics#drawChars
      */
     public void drawString(String str, int x, int y){
         drawString(str, (float)x, (float)y);
@@ -477,7 +462,7 @@
      *                     of the oval to be filled.
      * @param       width the width of the oval to be filled.
      * @param       height the height of the oval to be filled.
-     * @see         java.awt.Graphics#drawOval
+     * @see         Graphics#drawOval
      */
     public void fillOval(int x, int y, int width, int height){
         Ellipse2D oval = new Ellipse2D.Double(x, y, width, height);
@@ -498,7 +483,7 @@
      *                     of the arc at the four corners.
      * @param       arcHeight the vertical diameter
      *                     of the arc at the four corners.
-     * @see         java.awt.Graphics#drawRoundRect
+     * @see         Graphics#drawRoundRect
      */
     public void fillRoundRect(int x, int y, int width, int height,
                               int arcWidth, int arcHeight){
@@ -541,7 +526,7 @@
      * @param        startAngle the beginning angle.
      * @param        arcAngle the angular extent of the arc,
      *                    relative to the start angle.
-     * @see         java.awt.Graphics#drawArc
+     * @see         Graphics#drawArc
      */
     public void fillArc(int x, int y, int width, int height, int startAngle, int arcAngle){
         Arc2D arc = new Arc2D.Double(x, y, width, height, startAngle, arcAngle, Arc2D.PIE);
@@ -583,7 +568,7 @@
      * @param        startAngle the beginning angle.
      * @param        arcAngle the angular extent of the arc,
      *                    relative to the start angle.
-     * @see         java.awt.Graphics#fillArc
+     * @see         Graphics#fillArc
      */
     public void drawArc(int x, int y, int width, int height, int startAngle, int arcAngle) {
         Arc2D arc = new Arc2D.Double(x, y, width, height, startAngle, arcAngle, Arc2D.OPEN);
@@ -600,7 +585,7 @@
      * @param       xPoints an array of <i>x</i> points
      * @param       yPoints an array of <i>y</i> points
      * @param       nPoints the total number of points
-     * @see         java.awt.Graphics#drawPolygon(int[], int[], int)
+     * @see         Graphics#drawPolygon(int[], int[], int)
      * @since       JDK1.1
      */
     public void drawPolyline(int[] xPoints, int[] yPoints,
@@ -630,7 +615,7 @@
      *                     corner of the oval to be drawn.
      * @param       width the width of the oval to be drawn.
      * @param       height the height of the oval to be drawn.
-     * @see         java.awt.Graphics#fillOval
+     * @see         Graphics#fillOval
      */
     public void drawOval(int x, int y, int width, int height){
         Ellipse2D oval = new Ellipse2D.Double(x, y, width, height);
@@ -663,9 +648,9 @@
      *                         non-opaque portions of the image.
      * @param    observer    object to be notified as more of
      *                          the image is converted.
-     * @see      java.awt.Image
-     * @see      java.awt.image.ImageObserver
-     * @see      java.awt.image.ImageObserver#imageUpdate(java.awt.Image, int, int, int, int, int)
+     * @see      Image
+     * @see      ImageObserver
+     * @see      ImageObserver#imageUpdate(Image, int, int, int, int, int)
      */
     @NotImplemented
     public boolean drawImage(Image img, int x, int y,
@@ -709,9 +694,9 @@
      *                         non-opaque portions of the image.
      * @param    observer    object to be notified as more of
      *                          the image is converted.
-     * @see      java.awt.Image
-     * @see      java.awt.image.ImageObserver
-     * @see      java.awt.image.ImageObserver#imageUpdate(java.awt.Image, int, int, int, int, int)
+     * @see      Image
+     * @see      ImageObserver
+     * @see      ImageObserver#imageUpdate(Image, int, int, int, int, int)
      */
     @NotImplemented
     public boolean drawImage(Image img, int x, int y,
@@ -765,9 +750,9 @@
      *                    source rectangle.
      * @param       observer object to be notified as more of the image is
      *                    scaled and converted.
-     * @see         java.awt.Image
-     * @see         java.awt.image.ImageObserver
-     * @see         java.awt.image.ImageObserver#imageUpdate(java.awt.Image, int, int, int, int, int)
+     * @see         Image
+     * @see         ImageObserver
+     * @see         ImageObserver#imageUpdate(Image, int, int, int, int, int)
      * @since       JDK1.1
      */
     @NotImplemented
@@ -827,9 +812,9 @@
      *                    non-opaque portions of the image.
      * @param       observer object to be notified as more of the image is
      *                    scaled and converted.
-     * @see         java.awt.Image
-     * @see         java.awt.image.ImageObserver
-     * @see         java.awt.image.ImageObserver#imageUpdate(java.awt.Image, int, int, int, int, int)
+     * @see         Image
+     * @see         ImageObserver
+     * @see         ImageObserver#imageUpdate(Image, int, int, int, int, int)
      * @since       JDK1.1
      */
     @NotImplemented
@@ -870,9 +855,9 @@
      *                          the image is converted.
      * @return   <code>false</code> if the image pixels are still changing;
      *           <code>true</code> otherwise.
-     * @see      java.awt.Image
-     * @see      java.awt.image.ImageObserver
-     * @see      java.awt.image.ImageObserver#imageUpdate(java.awt.Image, int, int, int, int, int)
+     * @see      Image
+     * @see      ImageObserver
+     * @see      ImageObserver#imageUpdate(Image, int, int, int, int, int)
      */
     @NotImplemented
     public boolean drawImage(Image img, int x, int y,
@@ -902,11 +887,11 @@
      * call <code>dispose</code> when finished using
      * a <code>Graphics</code> object only if it was created
      * directly from a component or another <code>Graphics</code> object.
-     * @see         java.awt.Graphics#finalize
-     * @see         java.awt.Component#paint
-     * @see         java.awt.Component#update
-     * @see         java.awt.Component#getGraphics
-     * @see         java.awt.Graphics#create
+     * @see         Graphics#finalize
+     * @see         Component#paint
+     * @see         Component#update
+     * @see         Component#getGraphics
+     * @see         Graphics#create
      */
     public void dispose() {
     }
@@ -943,11 +928,11 @@
      * @param        xPoints   a an array of <code>x</code> coordinates.
      * @param        yPoints   a an array of <code>y</code> coordinates.
      * @param        nPoints   a the total number of points.
-     * @see          java.awt.Graphics#drawPolygon(int[], int[], int)
+     * @see          Graphics#drawPolygon(int[], int[], int)
      */
     public void fillPolygon(int[] xPoints, int[] yPoints,
                             int nPoints){
-        java.awt.Polygon polygon = new java.awt.Polygon(xPoints, yPoints, nPoints);
+        Polygon polygon = new Polygon(xPoints, yPoints, nPoints);
         fill(polygon);
     }
 
@@ -967,8 +952,8 @@
      *                         of the rectangle to be filled.
      * @param         width   the width of the rectangle to be filled.
      * @param         height   the height of the rectangle to be filled.
-     * @see           java.awt.Graphics#clearRect
-     * @see           java.awt.Graphics#drawRect
+     * @see           Graphics#clearRect
+     * @see           Graphics#drawRect
      */
     public void fillRect(int x, int y, int width, int height){
         Rectangle rect = new Rectangle(x, y, width, height);
@@ -988,8 +973,8 @@
      *                         of the rectangle to be drawn.
      * @param         width   the width of the rectangle to be drawn.
      * @param         height   the height of the rectangle to be drawn.
-     * @see          java.awt.Graphics#fillRect
-     * @see          java.awt.Graphics#clearRect
+     * @see          Graphics#fillRect
+     * @see          Graphics#clearRect
      */
     public void drawRect(int x, int y, int width, int height) {
         Rectangle rect = new Rectangle(x, y, width, height);
@@ -1012,12 +997,12 @@
      * @param        xPoints   a an array of <code>x</code> coordinates.
      * @param        yPoints   a an array of <code>y</code> coordinates.
      * @param        nPoints   a the total number of points.
-     * @see          java.awt.Graphics#fillPolygon(int[],int[],int)
-     * @see          java.awt.Graphics#drawPolyline
+     * @see          Graphics#fillPolygon(int[],int[],int)
+     * @see          Graphics#drawPolyline
      */
     public void drawPolygon(int[] xPoints, int[] yPoints,
                             int nPoints){
-        java.awt.Polygon polygon = new java.awt.Polygon(xPoints, yPoints, nPoints);
+        Polygon polygon = new Polygon(xPoints, yPoints, nPoints);
         draw(polygon);
     }
 
@@ -1055,9 +1040,9 @@
      * user clip, which is independent of the clipping associated
      * with device bounds and window visibility.
      * @param clip the <code>Shape</code> to use to set the clip
-     * @see         java.awt.Graphics#getClip()
-     * @see         java.awt.Graphics#clipRect
-     * @see         java.awt.Graphics#setClip(int, int, int, int)
+     * @see         Graphics#getClip()
+     * @see         Graphics#clipRect
+     * @see         Graphics#setClip(int, int, int, int)
      * @since       JDK1.1
      */
     @NotImplemented
@@ -1076,10 +1061,10 @@
      * system origin of this graphics context.
      * @return      the bounding rectangle of the current clipping area,
      *              or <code>null</code> if no clip is set.
-     * @see         java.awt.Graphics#getClip
-     * @see         java.awt.Graphics#clipRect
-     * @see         java.awt.Graphics#setClip(int, int, int, int)
-     * @see         java.awt.Graphics#setClip(Shape)
+     * @see         Graphics#getClip
+     * @see         Graphics#clipRect
+     * @see         Graphics#setClip(int, int, int, int)
+     * @see         Graphics#setClip(Shape)
      * @since       JDK1.1
      */
     public Rectangle getClipBounds(){
@@ -1096,8 +1081,8 @@
      * @param       iterator the iterator whose text is to be drawn
      * @param       x        the <i>x</i> coordinate.
      * @param       y        the <i>y</i> coordinate.
-     * @see         java.awt.Graphics#drawBytes
-     * @see         java.awt.Graphics#drawChars
+     * @see         Graphics#drawBytes
+     * @see         Graphics#drawChars
      */
     public void drawString(AttributedCharacterIterator iterator,
                            int x, int y){
@@ -1117,11 +1102,11 @@
      * @param       y the <i>y</i> coordinate of the rectangle to clear.
      * @param       width the width of the rectangle to clear.
      * @param       height the height of the rectangle to clear.
-     * @see         java.awt.Graphics#fillRect(int, int, int, int)
-     * @see         java.awt.Graphics#drawRect
-     * @see         java.awt.Graphics#setColor(java.awt.Color)
-     * @see         java.awt.Graphics#setPaintMode
-     * @see         java.awt.Graphics#setXORMode(java.awt.Color)
+     * @see         Graphics#fillRect(int, int, int, int)
+     * @see         Graphics#drawRect
+     * @see         Graphics#setColor(Color)
+     * @see         Graphics#setPaintMode
+     * @see         Graphics#setXORMode(Color)
      */
     public void clearRect(int x, int y, int width, int height) {
         Paint paint = getPaint();
@@ -1143,8 +1128,8 @@
      * @param       y the <i>y</i> coordinate of the new clip rectangle.
      * @param       width the width of the new clip rectangle.
      * @param       height the height of the new clip rectangle.
-     * @see         java.awt.Graphics#clipRect
-     * @see         java.awt.Graphics#setClip(Shape)
+     * @see         Graphics#clipRect
+     * @see         Graphics#setClip(Shape)
      * @since       JDK1.1
      */
     public void setClip(int x, int y, int width, int height){
@@ -1232,9 +1217,9 @@
      * the text rendering.
      *
      * @return a reference to an instance of FontRenderContext.
-     * @see java.awt.font.FontRenderContext
-     * @see java.awt.Font#createGlyphVector(FontRenderContext,char[])
-     * @see java.awt.font.TextLayout
+     * @see FontRenderContext
+     * @see Font#createGlyphVector(FontRenderContext,char[])
+     * @see TextLayout
      * @since     JDK1.2
      */
     public FontRenderContext getFontRenderContext() {
@@ -1311,7 +1296,7 @@
      * @param color the background color that isused in
      * subsequent calls to <code>clearRect</code>
      * @see #getBackground
-     * @see java.awt.Graphics#clearRect
+     * @see Graphics#clearRect
      */
     public void setBackground(Color color) {
         if(color == null)
@@ -1351,9 +1336,9 @@
      *         used to render to the screen and a security manager
      *         is set and its <code>checkPermission</code> method
      *         does not allow the operation.
-     * @see java.awt.Graphics#setXORMode
-     * @see java.awt.Graphics#setPaintMode
-     * @see java.awt.AlphaComposite
+     * @see Graphics#setXORMode
+     * @see Graphics#setPaintMode
+     * @see AlphaComposite
      */
     @NotImplemented
     public void setComposite(Composite comp){
@@ -1423,10 +1408,10 @@
      * @param y the y position in user space where the glyphs should be
      *        rendered
      *
-     * @see java.awt.Font#createGlyphVector(FontRenderContext, char[])
-     * @see java.awt.font.GlyphVector
+     * @see Font#createGlyphVector(FontRenderContext, char[])
+     * @see GlyphVector
      * @see #setPaint
-     * @see java.awt.Graphics#setColor
+     * @see Graphics#setColor
      * @see #setTransform
      * @see #setComposite
      * @see #setClip(Shape)
@@ -1504,7 +1489,7 @@
      * @param y the y coordinate where the iterator's text is to be
      * rendered
      * @see #setPaint
-     * @see java.awt.Graphics#setColor
+     * @see Graphics#setColor
      * @see #setTransform
      * @see #setComposite
      * @see #setClip
@@ -1652,9 +1637,9 @@
      *                          the image is converted.
      * @return   <code>false</code> if the image pixels are still changing;
      *           <code>true</code> otherwise.
-     * @see      java.awt.Image
-     * @see      java.awt.image.ImageObserver
-     * @see      java.awt.image.ImageObserver#imageUpdate(java.awt.Image, int, int, int, int, int)
+     * @see      Image
+     * @see      ImageObserver
+     * @see      ImageObserver#imageUpdate(Image, int, int, int, int, int)
      */
     @NotImplemented
     public boolean drawImage(Image img, int x, int y,
@@ -1682,9 +1667,9 @@
      * Gets the font metrics for the specified font.
      * @return    the font metrics for the specified font.
      * @param     f the specified font
-     * @see       java.awt.Graphics#getFont
-     * @see       java.awt.FontMetrics
-     * @see       java.awt.Graphics#getFontMetrics()
+     * @see       Graphics#getFont
+     * @see       FontMetrics
+     * @see       Graphics#getFontMetrics()
      */
     @SuppressWarnings("deprecation")
     @SuppressForbidden
@@ -1805,8 +1790,6 @@
     }
 
     private void logNotImplemented() {
-        if (LOG.check(POILogger.WARN)) {
-            LOG.log(POILogger.WARN, "Not implemented");
-        }
+        LOG.atWarn().log("Not implemented");
     }
 }
diff --git a/src/java/org/apache/poi/sl/draw/geom/PresetGeometries.java b/src/java/org/apache/poi/sl/draw/geom/PresetGeometries.java
index 13e3992..acde02c 100644
--- a/src/java/org/apache/poi/sl/draw/geom/PresetGeometries.java
+++ b/src/java/org/apache/poi/sl/draw/geom/PresetGeometries.java
@@ -31,12 +31,12 @@
 import javax.xml.stream.XMLStreamReader;
 import javax.xml.transform.stream.StreamSource;
 
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.apache.poi.util.XMLHelper;
 
 public final class PresetGeometries {
-    private static final POILogger LOG = POILogFactory.getLogger(PresetGeometries.class);
+    private static final Logger LOG = LogManager.getLogger(PresetGeometries.class);
 
     private final Map<String, CustomGeometry> map = new TreeMap<>();
 
@@ -76,7 +76,7 @@
             p.parse(staxReader);
             return p.getGeom().values().stream().findFirst().orElse(null);
         } catch (XMLStreamException e) {
-            LOG.log(POILogger.ERROR, "Unable to parse single custom geometry", e);
+            LOG.atError().withThrowable(e).log("Unable to parse single custom geometry");
             return null;
         }
     }
diff --git a/src/java/org/apache/poi/sl/draw/geom/PresetParser.java b/src/java/org/apache/poi/sl/draw/geom/PresetParser.java
index 9cfa06b..998b0ee 100644
--- a/src/java/org/apache/poi/sl/draw/geom/PresetParser.java
+++ b/src/java/org/apache/poi/sl/draw/geom/PresetParser.java
@@ -27,10 +27,10 @@
 import javax.xml.stream.XMLStreamException;
 import javax.xml.stream.XMLStreamReader;
 
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.apache.poi.sl.usermodel.PaintStyle.PaintModifier;
 import org.apache.poi.util.Internal;
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
 
 @Internal
 class PresetParser {
@@ -55,7 +55,7 @@
         }
     }
 
-    private static final POILogger LOG = POILogFactory.getLogger(PresetParser.class);
+    private static final Logger LOG = LogManager.getLogger(PresetParser.class);
 
     private Mode mode;
 
@@ -104,7 +104,7 @@
         final String name = sr.getLocalName();
         customGeometry = new CustomGeometry();
         if (geom.containsKey(name)) {
-            LOG.log(POILogger.WARN, "Duplicate definition of " + name);
+            LOG.atWarn().log("Duplicate definition of {}", name);
         }
         geom.put(name, customGeometry);
         mode = Mode.SHAPE;
diff --git a/src/java/org/apache/poi/sl/extractor/SlideShowExtractor.java b/src/java/org/apache/poi/sl/extractor/SlideShowExtractor.java
index fa45450..fabab5a 100644
--- a/src/java/org/apache/poi/sl/extractor/SlideShowExtractor.java
+++ b/src/java/org/apache/poi/sl/extractor/SlideShowExtractor.java
@@ -26,6 +26,8 @@
 import java.util.function.Predicate;
 
 import com.zaxxer.sparsebits.SparseBitSet;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.apache.poi.extractor.POITextExtractor;
 import org.apache.poi.sl.usermodel.MasterSheet;
 import org.apache.poi.sl.usermodel.Notes;
@@ -43,8 +45,6 @@
 import org.apache.poi.sl.usermodel.TextRun;
 import org.apache.poi.sl.usermodel.TextShape;
 import org.apache.poi.util.LocaleUtil;
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
 
 /**
  * Common SlideShow extractor
@@ -55,7 +55,7 @@
     S extends Shape<S,P>,
     P extends TextParagraph<S,P,? extends TextRun>
 > implements POITextExtractor {
-    private static final POILogger LOG = POILogFactory.getLogger(SlideShowExtractor.class);
+    private static final Logger LOG = LogManager.getLogger(SlideShowExtractor.class);
 
     // placeholder text for slide numbers
     private static final String SLIDE_NUMBER_PH = "‹#›";
@@ -178,7 +178,7 @@
 
                 if (ts.isPlaceholder()) {
                     // don't bother about boiler plate text on master sheets
-                    LOG.log(POILogger.INFO, "Ignoring boiler plate (placeholder) text on slide master:", text);
+                    LOG.atInfo().log("Ignoring boiler plate (placeholder) text on slide master: {}", text);
                     continue;
                 }
 
diff --git a/src/java/org/apache/poi/sl/image/ImageHeaderBitmap.java b/src/java/org/apache/poi/sl/image/ImageHeaderBitmap.java
index c6283b6..b7d0a3c 100644
--- a/src/java/org/apache/poi/sl/image/ImageHeaderBitmap.java
+++ b/src/java/org/apache/poi/sl/image/ImageHeaderBitmap.java
@@ -24,15 +24,15 @@
 
 import javax.imageio.ImageIO;
 
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.apache.poi.util.Internal;
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
 import org.apache.poi.util.Units;
 
 @Internal
 public class ImageHeaderBitmap {
-    private static final POILogger LOG = POILogFactory.getLogger(ImageHeaderBitmap.class);
-    
+    private static final Logger LOG = LogManager.getLogger(ImageHeaderBitmap.class);
+
     private final Dimension size;
     
     public ImageHeaderBitmap(byte[] data, int offset) {
@@ -40,7 +40,7 @@
         try {
             img = ImageIO.read(new ByteArrayInputStream(data, offset, data.length-offset));
         } catch (IOException e) {
-            LOG.log(POILogger.WARN, "Can't determine image dimensions", e);
+            LOG.atWarn().withThrowable(e).log("Can't determine image dimensions");
         }
         // set dummy size, in case of dummy dimension can't be set
         size = (img == null)
diff --git a/src/java/org/apache/poi/sl/image/ImageHeaderEMF.java b/src/java/org/apache/poi/sl/image/ImageHeaderEMF.java
index 48bf455..6dd5faf 100644
--- a/src/java/org/apache/poi/sl/image/ImageHeaderEMF.java
+++ b/src/java/org/apache/poi/sl/image/ImageHeaderEMF.java
@@ -20,15 +20,15 @@
 import java.awt.Dimension;
 import java.awt.Rectangle;
 
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.apache.poi.util.Internal;
 import org.apache.poi.util.LittleEndian;
 import org.apache.poi.util.LocaleUtil;
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
 
 @Internal
 public class ImageHeaderEMF {
-    private static final POILogger LOG = POILogFactory.getLogger(ImageHeaderEMF.class);
+    private static final Logger LOG = LogManager.getLogger(ImageHeaderEMF.class);
 
     private static final String EMF_SIGNATURE = " EMF"; // 0x464D4520 (LE)
 
@@ -40,7 +40,7 @@
         int offset = off;
         int type = (int)LittleEndian.getUInt(data, offset); offset += 4;
         if (type != 1) {
-            LOG.log(POILogger.WARN, "Invalid EMF picture - invalid type");
+            LOG.atWarn().log("Invalid EMF picture - invalid type");
             deviceBounds = new Rectangle(0,0,200,200);
             return;
         }
@@ -55,7 +55,7 @@
         offset += 16;
         String signature = new String(data, offset, EMF_SIGNATURE.length(), LocaleUtil.CHARSET_1252);
         if (!EMF_SIGNATURE.equals(signature)) {
-            LOG.log(POILogger.WARN, "Invalid EMF picture - invalid signature");
+            LOG.atWarn().log("Invalid EMF picture - invalid signature");
         }
     }
 
diff --git a/src/java/org/apache/poi/sl/image/ImageHeaderWMF.java b/src/java/org/apache/poi/sl/image/ImageHeaderWMF.java
index d210bc5..cf2f758 100644
--- a/src/java/org/apache/poi/sl/image/ImageHeaderWMF.java
+++ b/src/java/org/apache/poi/sl/image/ImageHeaderWMF.java
@@ -22,11 +22,11 @@
 import java.io.IOException;
 import java.io.OutputStream;
 
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.apache.poi.util.Internal;
 import org.apache.poi.util.LittleEndian;
 import org.apache.poi.util.LittleEndianConsts;
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
 import org.apache.poi.util.Units;
 
 /**
@@ -47,7 +47,7 @@
 public class ImageHeaderWMF {
 
     public static final int APMHEADER_KEY = 0x9AC6CDD7;
-    private static final POILogger LOG = POILogFactory.getLogger(ImageHeaderWMF.class);
+    private static final Logger LOG = LogManager.getLogger(ImageHeaderWMF.class);
 
     @SuppressWarnings("unused")
     private final int handle;
@@ -80,7 +80,7 @@
         int offset = off;
         int key = LittleEndian.getInt(data, offset); offset += LittleEndianConsts.INT_SIZE; //header key
         if (key != APMHEADER_KEY) {
-            LOG.log(POILogger.WARN, "WMF file doesn't contain a placeable header - ignore parsing");
+            LOG.atWarn().log("WMF file doesn't contain a placeable header - ignore parsing");
             handle = 0;
             left = 0;
             top = 0;
@@ -102,7 +102,7 @@
 
         checksum = LittleEndian.getShort(data, offset); offset += LittleEndianConsts.SHORT_SIZE;
         if (checksum != getChecksum()){
-            LOG.log(POILogger.WARN, "WMF checksum does not match the header data");
+            LOG.atWarn().log("WMF checksum does not match the header data");
         }
     }
 
diff --git a/src/java/org/apache/poi/sl/usermodel/ObjectData.java b/src/java/org/apache/poi/sl/usermodel/ObjectData.java
index db30a9b..11a9428 100644
--- a/src/java/org/apache/poi/sl/usermodel/ObjectData.java
+++ b/src/java/org/apache/poi/sl/usermodel/ObjectData.java
@@ -21,12 +21,12 @@
 import java.io.InputStream;
 import java.io.OutputStream;
 
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.apache.poi.poifs.filesystem.DirectoryEntry;
 import org.apache.poi.poifs.filesystem.FileMagic;
 import org.apache.poi.poifs.filesystem.POIFSFileSystem;
 import org.apache.poi.util.IOUtils;
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
 
 /**
  * Common interface for OLE shapes, i.e. shapes linked to embedded documents
@@ -68,8 +68,8 @@
             FileMagic fm = FileMagic.valueOf(is);
             return fm == FileMagic.OLE2;
         } catch (IOException e) {
-            POILogger LOG = POILogFactory.getLogger(ObjectData.class);
-            LOG.log(POILogger.WARN, "Can't determine filemagic of ole stream", e);
+            Logger LOG = LogManager.getLogger(ObjectData.class);
+            LOG.atWarn().withThrowable(e).log("Can't determine filemagic of ole stream");
             return false;
         }
     }
diff --git a/src/java/org/apache/poi/ss/extractor/EmbeddedExtractor.java b/src/java/org/apache/poi/ss/extractor/EmbeddedExtractor.java
index 153733f..dbce024 100644
--- a/src/java/org/apache/poi/ss/extractor/EmbeddedExtractor.java
+++ b/src/java/org/apache/poi/ss/extractor/EmbeddedExtractor.java
@@ -28,6 +28,8 @@
 import java.util.Iterator;
 import java.util.List;
 
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.apache.poi.hpsf.ClassID;
 import org.apache.poi.hpsf.ClassIDPredefined;
 import org.apache.poi.poifs.filesystem.DirectoryNode;
@@ -47,8 +49,6 @@
 import org.apache.poi.util.Beta;
 import org.apache.poi.util.IOUtils;
 import org.apache.poi.util.LocaleUtil;
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
 
 /**
  * This extractor class tries to identify various embedded documents within Excel files
@@ -56,7 +56,7 @@
  */
 @Beta
 public class EmbeddedExtractor implements Iterable<EmbeddedExtractor> {
-    private static final POILogger LOG = POILogFactory.getLogger(EmbeddedExtractor.class);
+    private static final Logger LOG = LogManager.getLogger(EmbeddedExtractor.class);
     //arbitrarily selected; may need to increase
     private static final int MAX_RECORD_LENGTH = 1_000_000;
 
@@ -117,7 +117,7 @@
                         data = new EmbeddedData(od.getFileName(), od.getObjectData(), od.getContentType());
                     }
                 } catch (Exception e) {
-                    LOG.log(POILogger.WARN, "Entry not found / readable - ignoring OLE embedding", e);
+                    LOG.atWarn().withThrowable(e).log("Entry not found / readable - ignoring OLE embedding");
                 }
             } else if (shape instanceof Picture) {
                 data = extractOne((Picture)shape);
diff --git a/src/java/org/apache/poi/ss/format/CellNumberFormatter.java b/src/java/org/apache/poi/ss/format/CellNumberFormatter.java
index 901a65c..f25965a 100644
--- a/src/java/org/apache/poi/ss/format/CellNumberFormatter.java
+++ b/src/java/org/apache/poi/ss/format/CellNumberFormatter.java
@@ -32,15 +32,15 @@
 import java.util.TreeSet;
 
 import com.zaxxer.sparsebits.SparseBitSet;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.apache.poi.util.LocaleUtil;
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
 
 /**
  * This class implements printing out a value using a number format.
  */
 public class CellNumberFormatter extends CellFormatter {
-    private static final POILogger LOG = POILogFactory.getLogger(CellNumberFormatter.class);
+    private static final Logger LOG = LogManager.getLogger(CellNumberFormatter.class);
 
     private final String desc;
     private final String printfFmt;
@@ -695,8 +695,8 @@
             }
             writeSingleInteger(numeratorFmt, n, output, numeratorSpecials, mods);
             writeSingleInteger(denominatorFmt, d, output, denominatorSpecials, mods);
-        } catch (RuntimeException ignored) {
-            LOG.log(POILogger.ERROR, "error while fraction evaluation", ignored);
+        } catch (RuntimeException e) {
+            LOG.atError().withThrowable(e).log("error while fraction evaluation");
         }
     }
 
diff --git a/src/java/org/apache/poi/ss/formula/FormulaParser.java b/src/java/org/apache/poi/ss/formula/FormulaParser.java
index b7cab41..a05166e 100644
--- a/src/java/org/apache/poi/ss/formula/FormulaParser.java
+++ b/src/java/org/apache/poi/ss/formula/FormulaParser.java
@@ -22,6 +22,10 @@
 import java.util.Locale;
 import java.util.regex.Pattern;
 
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+import org.apache.poi.hssf.usermodel.HSSFFormulaEvaluator;
+import org.apache.poi.hssf.usermodel.HSSFWorkbook;
 import org.apache.poi.ss.SpreadsheetVersion;
 import org.apache.poi.ss.formula.constant.ErrorConstant;
 import org.apache.poi.ss.formula.function.FunctionMetadata;
@@ -71,12 +75,11 @@
 import org.apache.poi.ss.usermodel.FormulaError;
 import org.apache.poi.ss.usermodel.Name;
 import org.apache.poi.ss.usermodel.Table;
+import org.apache.poi.ss.usermodel.Workbook;
 import org.apache.poi.ss.util.AreaReference;
 import org.apache.poi.ss.util.CellReference;
 import org.apache.poi.ss.util.CellReference.NameType;
 import org.apache.poi.util.Internal;
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
 
 /**
  * This class parses a formula string into a List of tokens in RPN order.
@@ -93,7 +96,7 @@
  */
 @Internal
 public final class FormulaParser {
-    private static final POILogger log = POILogFactory.getLogger(FormulaParser.class);
+    private static final Logger LOGGER = LogManager.getLogger(FormulaParser.class);
     private final String _formulaString;
     private final int _formulaLength;
     /** points at the next character to be read (after the {@link #look} codepoint) */
@@ -132,9 +135,9 @@
      *  parse results.
      * This class is recommended only for single threaded use.
      *
-     * If you have a {@link org.apache.poi.hssf.usermodel.HSSFWorkbook}, and not a
-     *  {@link org.apache.poi.ss.usermodel.Workbook}, then use the convenience method on
-     *  {@link org.apache.poi.hssf.usermodel.HSSFFormulaEvaluator}
+     * If you have a {@link HSSFWorkbook}, and not a
+     *  {@link Workbook}, then use the convenience method on
+     *  {@link HSSFFormulaEvaluator}
      */
     private FormulaParser(String formula, FormulaParsingWorkbook book, int sheetIndex, int rowIndex) {
         _formulaString = formula;
@@ -148,7 +151,7 @@
 
     /**
      * Parse a formula into an array of tokens
-     * Side effect: creates name ({@link org.apache.poi.ss.usermodel.Workbook#createName})
+     * Side effect: creates name ({@link Workbook#createName})
      *     if formula contains unrecognized names (names are likely UDFs)
      *
      * @param formula     the formula to parse
@@ -173,7 +176,7 @@
 
     /**
      * Parse a formula into an array of tokens
-     * Side effect: creates name ({@link org.apache.poi.ss.usermodel.Workbook#createName})
+     * Side effect: creates name ({@link Workbook#createName})
      *     if formula contains unrecognized names (names are likely UDFs)
      *
      * @param formula     the formula to parse
@@ -1012,7 +1015,7 @@
     /**
      * Matches a zero or one letter-runs followed by zero or one digit-runs.
      * Either or both runs man optionally be prefixed with a single '$'.
-     * (copied+modified from {@link org.apache.poi.ss.util.CellReference#CELL_REF_PATTERN})
+     * (copied+modified from {@link CellReference#CELL_REF_PATTERN})
      */
     private static final Pattern CELL_REF_PATTERN = Pattern.compile("(\\$?[A-Za-z]+)?(\\$?[0-9]+)?");
 
@@ -1325,10 +1328,7 @@
                 nameToken = _book.getNameXPtg(name, null);
                 if (nameToken == null) {
                     // name is not an internal or external name
-                    if (log.check(POILogger.WARN)) {
-                        log.log(POILogger.WARN,
-                                "FormulaParser.function: Name '" + name + "' is completely unknown in the current workbook.");
-                    }
+                    LOGGER.atWarn().log("FormulaParser.function: Name '{}' is completely unknown in the current workbook.", name);
                     // name is probably the name of an unregistered User-Defined Function
                     switch (_book.getSpreadsheetVersion()) {
                         case EXCEL97:
diff --git a/src/java/org/apache/poi/ss/formula/WorkbookEvaluator.java b/src/java/org/apache/poi/ss/formula/WorkbookEvaluator.java
index fa8dec3..8cb4cbf 100644
--- a/src/java/org/apache/poi/ss/formula/WorkbookEvaluator.java
+++ b/src/java/org/apache/poi/ss/formula/WorkbookEvaluator.java
@@ -25,6 +25,9 @@
 import java.util.Stack;
 import java.util.TreeSet;
 
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+import org.apache.logging.log4j.message.SimpleMessage;
 import org.apache.poi.ss.SpreadsheetVersion;
 import org.apache.poi.ss.formula.CollaboratingWorkbooksEnvironment.WorkbookNotFoundException;
 import org.apache.poi.ss.formula.atp.AnalysisToolPak;
@@ -38,8 +41,9 @@
 import org.apache.poi.ss.util.CellRangeAddressBase;
 import org.apache.poi.ss.util.CellReference;
 import org.apache.poi.util.Internal;
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
+
+import static org.apache.logging.log4j.util.Unbox.box;
+
 /**
  * Evaluates formula cells.<p/>
  *
@@ -55,7 +59,7 @@
 @Internal
 public final class WorkbookEvaluator {
     
-    private static final POILogger LOG = POILogFactory.getLogger(WorkbookEvaluator.class);
+    private static final Logger LOG = LogManager.getLogger(WorkbookEvaluator.class);
 
     private final EvaluationWorkbook _workbook;
     private EvaluationCache _cache;
@@ -77,7 +81,7 @@
     private boolean dbgEvaluationOutputForNextEval;
 
     // special logger for formula evaluation output (because of possibly very large output)
-    private final POILogger EVAL_LOG = POILogFactory.getLogger("POI.FormulaEval");
+    private final Logger EVAL_LOG = LogManager.getLogger("POI.FormulaEval");
     // current indent level for evalution; negative value for no output
     private int dbgEvaluationOutputIndent = -1;
 
@@ -125,22 +129,6 @@
         return _workbook.getName(name, sheetIndex);
     }
 
-    private static boolean isDebugLogEnabled() {
-        return LOG.check(POILogger.DEBUG);
-    }
-    private static boolean isInfoLogEnabled() {
-        return LOG.check(POILogger.INFO);
-    }
-    private static void logDebug(String s) {
-        if (isDebugLogEnabled()) {
-            LOG.log(POILogger.DEBUG, s);
-        }
-    }
-    private static void logInfo(String s) {
-        if (isInfoLogEnabled()) {
-            LOG.log(POILogger.INFO, s);
-        }
-    }
     /* package */ void attachToEnvironment(CollaboratingWorkbooksEnvironment collaboratingWorkbooksEnvironment, EvaluationCache cache, int workbookIx) {
         _collaboratingWorkbookEnvironment = collaboratingWorkbooksEnvironment;
         _cache = cache;
@@ -285,7 +273,7 @@
                 throw addExceptionInfo(e, sheetIndex, rowIndex, columnIndex);
              } catch (RuntimeException re) {
                  if (re.getCause() instanceof WorkbookNotFoundException && _ignoreMissingWorkbooks) {
-                     logInfo(re.getCause().getMessage() + " - Continuing with cached value!");
+                     LOG.atInfo().log("{} - Continuing with cached value!", re.getCause().getMessage());
                      switch(srcCell.getCachedFormulaResultType()) {
                          case NUMERIC:
                              result = new NumberEval(srcCell.getNumericCellValue());
@@ -318,11 +306,12 @@
             }
             return cce.getValue();
         }
-        if (isDebugLogEnabled()) {
+        final ValueEval resultForLogging = result;
+        LOG.atDebug().log(()->{
             String sheetName = getSheetName(sheetIndex);
             CellReference cr = new CellReference(rowIndex, columnIndex);
-            logDebug("Evaluated " + sheetName + "!" + cr.formatAsString() + " to " + result);
-        }
+            return new SimpleMessage("Evaluated " + sheetName + "!" + cr.formatAsString() + " to " + resultForLogging);
+        });
         // Usually (result === cce.getValue())
         // But sometimes: (result==ErrorEval.CIRCULAR_REF_ERROR, cce.getValue()==null)
         // When circular references are detected, the cache entry is only updated for
@@ -344,7 +333,7 @@
             return new NotImplementedException(msg, inner);
         } catch (Exception e) {
             // avoid bombing out during exception handling
-            LOG.log(POILogger.ERROR, "Can't add exception info", e);
+            LOG.atError().withThrowable(e).log("Can't add exception info");
             return inner; // preserve original exception
         }
     }
@@ -387,14 +376,18 @@
             dbgEvaluationOutputForNextEval = false;
         }
         if (dbgEvaluationOutputIndent > 0) {
-            // init. indent string to needed spaces (create as substring vom very long space-only string;
-            // limit indendation for deep recursions)
+            // init. indent string to needed spaces (create as substring from very long space-only string;
+            // limit indentation for deep recursions)
             dbgIndentStr = "                                                                                                    ";
             dbgIndentStr = dbgIndentStr.substring(0, Math.min(dbgIndentStr.length(), dbgEvaluationOutputIndent*2));
-            EVAL_LOG.log(POILogger.WARN, dbgIndentStr
-                               + "- evaluateFormula('" + ec.getRefEvaluatorForCurrentSheet().getSheetNameRange()
-                               + "'/" + new CellReference(ec.getRowIndex(), ec.getColumnIndex()).formatAsString()
-                               + "): " + Arrays.toString(ptgs).replaceAll("\\Qorg.apache.poi.ss.formula.ptg.\\E", ""));
+            String finalDbgIndentStr = dbgIndentStr;
+            EVAL_LOG.atWarn().log(() -> {
+                String message = finalDbgIndentStr
+                        + "- evaluateFormula('" + ec.getRefEvaluatorForCurrentSheet().getSheetNameRange()
+                        + "'/" + new CellReference(ec.getRowIndex(), ec.getColumnIndex()).formatAsString()
+                        + "): " + Arrays.toString(ptgs).replaceAll("\\Qorg.apache.poi.ss.formula.ptg.\\E", "");
+                return new SimpleMessage(message);
+            });
             dbgEvaluationOutputIndent++;
         }
 
@@ -406,7 +399,7 @@
             // since we don't know how to handle these yet :(
             Ptg ptg = ptgs[i];
             if (dbgEvaluationOutputIndent > 0) {
-                EVAL_LOG.log(POILogger.INFO, dbgIndentStr, "  * ptg ", i, ": ", ptg, ", stack: ", stack);
+                EVAL_LOG.atInfo().log("{}  * ptg {}: {}, stack: {}", dbgIndentStr, box(i),ptg, stack);
             }
             if (ptg instanceof AttrPtg) {
                 AttrPtg attrPtg = (AttrPtg) ptg;
@@ -551,7 +544,7 @@
 //            logDebug("push " + opResult);
             stack.push(opResult);
             if (dbgEvaluationOutputIndent > 0) {
-                EVAL_LOG.log(POILogger.INFO, dbgIndentStr, "    = ", opResult);
+                EVAL_LOG.atInfo().log("{}    = {}", dbgIndentStr, opResult);
             }
         }
 
@@ -570,9 +563,7 @@
         }
 
         if (dbgEvaluationOutputIndent > 0) {
-            EVAL_LOG.log(POILogger.INFO, dbgIndentStr, "finished eval of ",
-                            new CellReference(ec.getRowIndex(), ec.getColumnIndex()).formatAsString(),
-                            ": ", result);
+            EVAL_LOG.atInfo().log("{}finished eval of {}: {}", dbgIndentStr, new CellReference(ec.getRowIndex(), ec.getColumnIndex()).formatAsString(), result);
             dbgEvaluationOutputIndent--;
             if (dbgEvaluationOutputIndent == 1) {
                 // this evaluation is done, reset indent to stop logging
diff --git a/src/java/org/apache/poi/ss/formula/constant/ErrorConstant.java b/src/java/org/apache/poi/ss/formula/constant/ErrorConstant.java
index 3d6641a..3d8fb50 100644
--- a/src/java/org/apache/poi/ss/formula/constant/ErrorConstant.java
+++ b/src/java/org/apache/poi/ss/formula/constant/ErrorConstant.java
@@ -17,9 +17,12 @@
 
 package org.apache.poi.ss.formula.constant;
 
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.apache.poi.ss.usermodel.FormulaError;
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
+
+import static org.apache.logging.log4j.util.Unbox.box;
+
 /**
  * Represents a constant error code value as encoded in a constant values array. <p>
  *
@@ -27,8 +30,8 @@
  * <tt>ErrorEval</tt>.
  */
 public final class ErrorConstant {
-	private static final POILogger LOG = POILogFactory.getLogger(ErrorConstant.class);
-    private static final ErrorConstant NULL = new ErrorConstant(FormulaError.NULL.getCode());
+	private static final Logger LOG = LogManager.getLogger(ErrorConstant.class);
+	private static final ErrorConstant NULL = new ErrorConstant(FormulaError.NULL.getCode());
     private static final ErrorConstant DIV_0 = new ErrorConstant(FormulaError.DIV0.getCode());
     private static final ErrorConstant VALUE = new ErrorConstant(FormulaError.VALUE.getCode());
     private static final ErrorConstant REF = new ErrorConstant(FormulaError.REF.getCode());
@@ -66,7 +69,7 @@
     			default:    break;
     		}
 	    }
-		LOG.log( POILogger.WARN, "Warning - unexpected error code (", errorCode, ")");
+		LOG.atWarn().log("Warning - unexpected error code ({})", box(errorCode));
 		return new ErrorConstant(errorCode);
 	}
 
diff --git a/src/java/org/apache/poi/ss/formula/functions/Rate.java b/src/java/org/apache/poi/ss/formula/functions/Rate.java
index 3b9de86..d0a840f 100644
--- a/src/java/org/apache/poi/ss/formula/functions/Rate.java
+++ b/src/java/org/apache/poi/ss/formula/functions/Rate.java
@@ -17,20 +17,20 @@
 
 package org.apache.poi.ss.formula.functions;
 
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.apache.poi.ss.formula.eval.ErrorEval;
 import org.apache.poi.ss.formula.eval.EvaluationException;
 import org.apache.poi.ss.formula.eval.NumberEval;
 import org.apache.poi.ss.formula.eval.OperandResolver;
 import org.apache.poi.ss.formula.eval.ValueEval;
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
 
 /**
  * Implements the Excel Rate function
  */
 public class Rate implements Function {
-    private static final POILogger LOG = POILogFactory.getLogger(Rate.class);
-    
+    private static final Logger LOG = LogManager.getLogger(Rate.class);
+
    public ValueEval evaluate(ValueEval[] args, int srcRowIndex, int srcColumnIndex) {
       if (args.length < 3) { //First 3 parameters are mandatory
          return ErrorEval.VALUE_INVALID;
@@ -65,7 +65,7 @@
 
          checkValue(rate);
       } catch (EvaluationException e) {
-          LOG.log(POILogger.ERROR, "Can't evaluate rate function", e);
+          LOG.atError().withThrowable(e).log("Can't evaluate rate function");
          return e.getErrorEval();
       }
 
diff --git a/src/java/org/apache/poi/ss/usermodel/DataFormatter.java b/src/java/org/apache/poi/ss/usermodel/DataFormatter.java
index a4c7e32..78bbd79 100644
--- a/src/java/org/apache/poi/ss/usermodel/DataFormatter.java
+++ b/src/java/org/apache/poi/ss/usermodel/DataFormatter.java
@@ -40,14 +40,14 @@
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.apache.poi.ss.format.CellFormat;
 import org.apache.poi.ss.format.CellFormatResult;
 import org.apache.poi.ss.formula.ConditionalFormattingEvaluator;
 import org.apache.poi.ss.util.DateFormatConverter;
 import org.apache.poi.ss.util.NumberToTextConverter;
 import org.apache.poi.util.LocaleUtil;
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
 
 
 /**
@@ -58,7 +58,7 @@
  * codes, etc.
  * <p>
  * Internally, formats will be implemented using subclasses of {@link Format}
- * such as {@link DecimalFormat} and {@link java.text.SimpleDateFormat}. Therefore the
+ * such as {@link DecimalFormat} and {@link SimpleDateFormat}. Therefore the
  * formats used by this class must obey the same pattern rules as these Format
  * subclasses. This means that only legal number pattern characters ("0", "#",
  * ".", "," etc.) may appear in number formats. Other characters can be
@@ -216,7 +216,7 @@
     private final PropertyChangeSupport pcs;
 
     /** For logging any problems we find */
-    private static final POILogger LOG = POILogFactory.getLogger(DataFormatter.class);
+    private static final Logger LOG = LogManager.getLogger(DataFormatter.class);
 
     /**
      * Creates a formatter using the {@link Locale#getDefault() default locale}.
@@ -337,7 +337,7 @@
                 // Wrap and return (non-cacheable - CellFormat does that)
                 return new CellFormatResultWrapper( cfmt.apply(cellValueO) );
             } catch (Exception e) {
-                LOG.log(POILogger.WARN, "Formatting failed for format " + formatStr + ", falling back", e);
+                LOG.atWarn().withThrowable(e).log("Formatting failed for format {}, falling back", formatStr);
             }
         }
 
@@ -598,7 +598,7 @@
         try {
             return new ExcelStyleDateFormatter(formatStr, dateSymbols);
         } catch(IllegalArgumentException iae) {
-            LOG.log(POILogger.DEBUG, "Formatting failed for format ", formatStr, ", falling back", iae);
+            LOG.atDebug().withThrowable(iae).log("Formatting failed for format {}, falling back", formatStr);
             // the pattern could not be parsed correctly,
             // so fall back to the default number format
             return getDefaultFormat(cellValue);
@@ -758,7 +758,7 @@
         try {
             return new InternalDecimalFormatWithScale(format, symbols);
         } catch(IllegalArgumentException iae) {
-            LOG.log(POILogger.DEBUG, "Formatting failed for format ", formatStr, ", falling back", iae);
+            LOG.atDebug().withThrowable(iae).log("Formatting failed for format {}, falling back", formatStr);
             // the pattern could not be parsed correctly,
             // so fall back to the default number format
             return getDefaultFormat(cellValue);
@@ -1044,7 +1044,7 @@
      * </p>
      *
      * @param format A Format instance to be used as a default
-     * @see java.text.Format#format
+     * @see Format#format
      */
     public void setDefaultNumberFormat(Format format) {
         for (Map.Entry<String, Format> entry : formats.entrySet()) {
diff --git a/src/java/org/apache/poi/ss/usermodel/FractionFormat.java b/src/java/org/apache/poi/ss/usermodel/FractionFormat.java
index eb6fa7b..c89838a 100644
--- a/src/java/org/apache/poi/ss/usermodel/FractionFormat.java
+++ b/src/java/org/apache/poi/ss/usermodel/FractionFormat.java
@@ -24,10 +24,10 @@
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.apache.poi.ss.format.SimpleFraction;
 import org.apache.poi.ss.formula.eval.NotImplementedException;
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
 
 /**
  * <p>Format class that handles Excel style fractions, such as "# #/#" and "#/###"</p>
@@ -43,7 +43,7 @@
 
 @SuppressWarnings("serial")
 public class FractionFormat extends Format {
-    private static final POILogger LOGGER = POILogFactory.getLogger(FractionFormat.class);
+    private static final Logger LOGGER = LogManager.getLogger(FractionFormat.class);
     private static final Pattern DENOM_FORMAT_PATTERN = Pattern.compile("(?:(#+)|(\\d+))");
 
     //this was chosen to match the earlier limitation of max denom power
@@ -147,7 +147,7 @@
                 fract = SimpleFraction.buildFractionMaxDenominator(decPart.doubleValue(), maxDenom);
             }
         } catch (RuntimeException e){
-            LOGGER.log(POILogger.WARN, "Can't format fraction", e);
+            LOGGER.atWarn().withThrowable(e).log("Can't format fraction");
             return Double.toString(doubleValue.doubleValue());
         }
 
diff --git a/src/java/org/apache/poi/ss/util/CellUtil.java b/src/java/org/apache/poi/ss/util/CellUtil.java
index 67823b5..4d5e3e0 100644
--- a/src/java/org/apache/poi/ss/util/CellUtil.java
+++ b/src/java/org/apache/poi/ss/util/CellUtil.java
@@ -25,6 +25,8 @@
 import java.util.Map;
 import java.util.Set;
 
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.apache.poi.ss.usermodel.BorderStyle;
 import org.apache.poi.ss.usermodel.Cell;
 import org.apache.poi.ss.usermodel.CellStyle;
@@ -35,8 +37,6 @@
 import org.apache.poi.ss.usermodel.Sheet;
 import org.apache.poi.ss.usermodel.VerticalAlignment;
 import org.apache.poi.ss.usermodel.Workbook;
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
 
 /**
  * Various utility functions that make working with a cells and rows easier. The various methods
@@ -50,7 +50,7 @@
  */
 public final class CellUtil {
     
-    private static final POILogger log = POILogFactory.getLogger(CellUtil.class);
+    private static final Logger LOGGER = LogManager.getLogger(CellUtil.class);
 
     // FIXME: Move these constants into an enum
     public static final String ALIGNMENT = "alignment";
@@ -258,7 +258,7 @@
      * <p>This is necessary because Excel has an upper limit on the number of styles that it supports.</p>
      * 
      * <p>This function is more efficient than multiple calls to
-     * {@link #setCellStyleProperty(org.apache.poi.ss.usermodel.Cell, String, Object)}
+     * {@link #setCellStyleProperty(Cell, String, Object)}
      * if adding multiple cell styles.</p>
      * 
      * <p>For performance reasons, if this is the only cell in a workbook that uses a cell style,
@@ -313,7 +313,7 @@
      * same style.</p>
      * 
      * <p>If setting more than one cell style property on a cell, use
-     * {@link #setCellStyleProperties(org.apache.poi.ss.usermodel.Cell, Map)},
+     * {@link #setCellStyleProperties(Cell, Map)},
      * which is faster and does not add unnecessary intermediate CellStyles to the workbook.</p>
      * 
      * @param cell The cell that is to be changed.
@@ -333,7 +333,7 @@
      *
      * @param style cell style
      * @return map of format properties (String -> Object)
-     * @see #setFormatProperties(org.apache.poi.ss.usermodel.CellStyle, org.apache.poi.ss.usermodel.Workbook, java.util.Map)
+     * @see #setFormatProperties(CellStyle, Workbook, Map)
      */
     private static Map<String, Object> getFormatProperties(CellStyle style) {
         Map<String, Object> properties = new HashMap<>();
@@ -385,7 +385,7 @@
             } else if (FILL_PATTERN.equals(key)) {
                 dest.put(key, getFillPattern(src, key));
             } else {
-                log.log(POILogger.INFO, "Ignoring unrecognized CellUtil format properties key: ", key);
+                LOGGER.atInfo().log("Ignoring unrecognized CellUtil format properties key: {}", key);
             }
         }
     }
@@ -468,10 +468,7 @@
         }
         // @deprecated 3.15 beta 2. getBorderStyle will only work on BorderStyle enums instead of codes in the future.
         else if (value instanceof Short) {
-            if (log.check(POILogger.WARN)) {
-                log.log(POILogger.WARN, "Deprecation warning: CellUtil properties map uses Short values for "
-                        + name + ". Should use BorderStyle enums instead.");
-            }
+            LOGGER.atWarn().log("Deprecation warning: CellUtil properties map uses Short values for {}. Should use BorderStyle enums instead.", name);
             short code = ((Short) value).shortValue();
             border = BorderStyle.valueOf(code);
         }
@@ -500,10 +497,7 @@
         }
         // @deprecated 3.15 beta 2. getFillPattern will only work on FillPatternType enums instead of codes in the future.
         else if (value instanceof Short) {
-            if (log.check(POILogger.WARN)) {
-                log.log(POILogger.WARN, "Deprecation warning: CellUtil properties map uses Short values for "
-                        + name + ". Should use FillPatternType enums instead.");
-            }
+            LOGGER.atWarn().log("Deprecation warning: CellUtil properties map uses Short values for {}. Should use FillPatternType enums instead.", name);
             short code = ((Short) value).shortValue();
             pattern = FillPatternType.forInt(code);
         }
@@ -532,10 +526,7 @@
         }
         // @deprecated 3.15 beta 2. getHorizontalAlignment will only work on HorizontalAlignment enums instead of codes in the future.
         else if (value instanceof Short) {
-            if (log.check(POILogger.WARN)) {
-                log.log(POILogger.WARN, "Deprecation warning: CellUtil properties map used a Short value for "
-                        + name + ". Should use HorizontalAlignment enums instead.");
-            }
+            LOGGER.atWarn().log("Deprecation warning: CellUtil properties map used a Short value for {}. Should use HorizontalAlignment enums instead.", name);
             short code = ((Short) value).shortValue();
             align = HorizontalAlignment.forInt(code);
         }
@@ -564,10 +555,7 @@
         }
         // @deprecated 3.15 beta 2. getVerticalAlignment will only work on VerticalAlignment enums instead of codes in the future.
         else if (value instanceof Short) {
-            if (log.check(POILogger.WARN)) {
-                log.log(POILogger.WARN, "Deprecation warning: CellUtil properties map used a Short value for "
-                        + name + ". Should use VerticalAlignment enums instead.");
-            }
+            LOGGER.atWarn().log("Deprecation warning: CellUtil properties map used a Short value for {}. Should use VerticalAlignment enums instead.", name);
             short code = ((Short) value).shortValue();
             align = VerticalAlignment.forInt(code);
         }
diff --git a/src/java/org/apache/poi/ss/util/DateFormatConverter.java b/src/java/org/apache/poi/ss/util/DateFormatConverter.java
index e338e84..47d1a04 100644
--- a/src/java/org/apache/poi/ss/util/DateFormatConverter.java
+++ b/src/java/org/apache/poi/ss/util/DateFormatConverter.java
@@ -24,9 +24,9 @@
 import java.util.Locale;
 import java.util.Map;
 
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.apache.poi.util.LocaleID;
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
 
 /**
  *  Convert java DateFormat patterns into Excel custom number formats.
@@ -49,7 +49,7 @@
  */
 @SuppressWarnings("unused")
 public final class DateFormatConverter  {
-	private static final POILogger LOG = POILogFactory.getLogger(DateFormatConverter.class);
+	private static final Logger LOG = LogManager.getLogger(DateFormatConverter.class);
 
 	private DateFormatConverter() {
 	}
@@ -155,7 +155,7 @@
 		}
 
 		if (loc == null) {
-			LOG.log(POILogger.ERROR, "Unable to find prefix for Locale '", languageTag, "' or its parent locales.");
+			LOG.atError().log("Unable to find prefix for Locale '{}' or its parent locales.", languageTag);
 			return "";
 		}
 
diff --git a/src/java/org/apache/poi/ss/util/ImageUtils.java b/src/java/org/apache/poi/ss/util/ImageUtils.java
index 8ab65b5..2b6a013 100644
--- a/src/java/org/apache/poi/ss/util/ImageUtils.java
+++ b/src/java/org/apache/poi/ss/util/ImageUtils.java
@@ -31,6 +31,8 @@
 import javax.imageio.ImageReader;
 import javax.imageio.stream.ImageInputStream;
 
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.apache.poi.hssf.usermodel.HSSFClientAnchor;
 import org.apache.poi.ss.usermodel.ClientAnchor;
 import org.apache.poi.ss.usermodel.Picture;
@@ -38,14 +40,12 @@
 import org.apache.poi.ss.usermodel.Row;
 import org.apache.poi.ss.usermodel.Sheet;
 import org.apache.poi.ss.usermodel.Workbook;
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
 import org.apache.poi.util.Units;
 import org.w3c.dom.Element;
 import org.w3c.dom.NodeList;
 
 public final class ImageUtils {
-    private static final POILogger LOG = POILogFactory.getLogger(ImageUtils.class);
+    private static final Logger LOG = LogManager.getLogger(ImageUtils.class);
 
     private static final int WIDTH_UNITS = 1024;
     private static final int HEIGHT_UNITS = 256;
@@ -56,8 +56,8 @@
      * Return the dimension of this image
      *
      * @param is the stream containing the image data
-     * @param type type of the picture: {@link org.apache.poi.ss.usermodel.Workbook#PICTURE_TYPE_JPEG},
-     * {@link org.apache.poi.ss.usermodel.Workbook#PICTURE_TYPE_PNG} or {@link org.apache.poi.ss.usermodel.Workbook#PICTURE_TYPE_DIB}
+     * @param type type of the picture: {@link Workbook#PICTURE_TYPE_JPEG},
+     * {@link Workbook#PICTURE_TYPE_PNG} or {@link Workbook#PICTURE_TYPE_DIB}
      *
      * @return image dimension in pixels
      */
@@ -93,18 +93,18 @@
                                 r.dispose();
                             }
                         } else {
-                            LOG.log(POILogger.WARN, "ImageIO found no images");
+                            LOG.atWarn().log("ImageIO found no images");
                         }
                     }
 
                 } catch (IOException e) {
                     //silently return if ImageIO failed to read the image
-                    LOG.log(POILogger.WARN, e);
+                    LOG.atWarn().withThrowable(e).log("Failed to determine image dimensions");
                 }
 
                 break;
             default:
-                LOG.log(POILogger.WARN, "Only JPEG, PNG and DIB pictures can be automatically sized");
+                LOG.atWarn().log("Only JPEG, PNG and DIB pictures can be automatically sized");
         }
         return size;
     }
diff --git a/src/java/org/apache/poi/util/CommonsLogger.java b/src/java/org/apache/poi/util/CommonsLogger.java
deleted file mode 100644
index cdc4f92..0000000
--- a/src/java/org/apache/poi/util/CommonsLogger.java
+++ /dev/null
@@ -1,177 +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.poi.util;
-
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-
-/**
- * An implementation of the {@link POILogger} using the
- * Apache Commons Logging framework. Which itself can be configured to
- * send log to various different log frameworks and even allows to create
- * a small wrapper for custom log frameworks.
- */
-public class CommonsLogger implements POILogger
-{
-    private static final LogFactory   _creator = LogFactory.getFactory();
-    private Log log;
-
-    @Override
-    public void initialize(final String cat) {
-        this.log = _creator.getInstance(cat);
-    }
-
-    /**
-     * Log a message
-     *
-     * @param level One of DEBUG, INFO, WARN, ERROR, FATAL
-     * @param obj1 The object to log.
-     */
-    @Override
-    public void _log(final int level, final Object obj1) {
-        // FIXME: What happens if level is in between two levels (an even number)?
-        // Should this be `if (level >= FATAL) ...`?
-        switch (level) {
-            case FATAL:
-                if (log.isFatalEnabled()) {
-                    log.fatal(obj1);
-                }
-                break;
-            case ERROR:
-                if (log.isErrorEnabled()) {
-                    log.error(obj1);
-                }
-                break;
-            case WARN:
-                if (log.isWarnEnabled()) {
-                    log.warn(obj1);
-                }
-                break;
-            case INFO:
-                if (log.isInfoEnabled()) {
-                    log.info(obj1);
-                }
-                break;
-            case DEBUG:
-                if (log.isDebugEnabled()) {
-                    log.debug(obj1);
-                }
-                break;
-            default:
-                if (log.isTraceEnabled()) {
-                    log.trace(obj1);
-                }
-                break;
-        }
-    }
-
-    /**
-     * Log a message
-     *
-     * @param level One of DEBUG, INFO, WARN, ERROR, FATAL
-     * @param obj1 The object to log.  This is converted to a string.
-     * @param exception An exception to be logged
-     */
-    @Override
-    public void _log(final int level, final Object obj1, final Throwable exception) {
-        // FIXME: What happens if level is in between two levels (an even number)?
-        // Should this be `if (level >= FATAL) ...`?
-        switch (level) {
-            case FATAL:
-                if (log.isFatalEnabled()) {
-                    if (obj1 != null) {
-                        log.fatal(obj1, exception);
-                    } else {
-                        log.fatal(exception);
-                    }
-                }
-                break;
-            case ERROR:
-                if (log.isErrorEnabled()) {
-                    if (obj1 != null) {
-                        log.error(obj1, exception);
-                    } else {
-                        log.error(exception);
-                    }
-                }
-                break;
-            case WARN:
-                if (log.isWarnEnabled()) {
-                    if (obj1 != null) {
-                        log.warn(obj1, exception);
-                    } else {
-                        log.warn(exception);
-                    }
-                }
-                break;
-            case INFO:
-                if (log.isInfoEnabled()) {
-                    if (obj1 != null) {
-                        log.info(obj1, exception);
-                    } else {
-                        log.info(exception);
-                    }
-                }
-                break;
-            case DEBUG:
-                if (log.isDebugEnabled()) {
-                    if (obj1 != null) {
-                        log.debug(obj1, exception);
-                    } else {
-                        log.debug(exception);
-                    }
-                }
-                break;
-            default:
-                if (log.isTraceEnabled()) {
-                    if (obj1 != null) {
-                        log.trace(obj1, exception);
-                    } else {
-                        log.trace(exception);
-                    }
-                }
-                break;
-        }
-    }
-
-    /**
-     * Check if a logger is enabled to log at the specified level
-     *
-     * @param level One of DEBUG, INFO, WARN, ERROR, FATAL
-     */
-    @Override
-    public boolean check(final int level)
-    {
-        // FIXME: What happens if level is in between two levels (an even number)?
-        // Should this be `if (level >= FATAL) ...`?
-        switch (level) {
-            case FATAL:
-                return log.isFatalEnabled();
-            case ERROR:
-                return log.isErrorEnabled();
-            case WARN:
-                return log.isWarnEnabled();
-            case INFO:
-                return log.isInfoEnabled();
-            case DEBUG:
-                return log.isDebugEnabled();
-            default:
-                return false;
-        }
-    }
-}
-
diff --git a/src/java/org/apache/poi/util/Configurator.java b/src/java/org/apache/poi/util/Configurator.java
index a8efb68..b82ad9b 100644
--- a/src/java/org/apache/poi/util/Configurator.java
+++ b/src/java/org/apache/poi/util/Configurator.java
@@ -17,11 +17,14 @@
    limitations under the License.
 ==================================================================== */
 
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+
 /**
  * Helper for fetching int values from system properties
  */
 public class Configurator {
-    private static final POILogger LOG = POILogFactory.getLogger(Configurator.class);
+    private static final Logger LOG = LogManager.getLogger(Configurator.class);
 
     public static int getIntValue(String systemProperty, int defaultValue) {
         String property = System.getProperty(systemProperty);
@@ -31,7 +34,7 @@
         try {
             return Integer.parseInt(property);
         } catch (Exception e) {
-            LOG.log(POILogger.ERROR, "System property -D", systemProperty, " does not contains a valid integer: ", property);
+            LOG.atError().log("System property -D{} does not contains a valid integer: {}", systemProperty, property);
             return defaultValue;
         }
     }
diff --git a/src/java/org/apache/poi/util/IOUtils.java b/src/java/org/apache/poi/util/IOUtils.java
index a578a2b..8e69427 100644
--- a/src/java/org/apache/poi/util/IOUtils.java
+++ b/src/java/org/apache/poi/util/IOUtils.java
@@ -33,11 +33,13 @@
 import java.util.zip.CRC32;
 import java.util.zip.Checksum;
 
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.apache.poi.EmptyFileException;
 
 @Internal
 public final class IOUtils {
-    private static final POILogger LOG = POILogFactory.getLogger( IOUtils.class );
+    private static final Logger LOG = LogManager.getLogger(IOUtils.class);
 
     /**
      * The default buffer size to use for the skip() methods.
@@ -395,8 +397,7 @@
         try {
             closeable.close();
         } catch ( Exception exc ) {
-            LOG.log( POILogger.ERROR, "Unable to close resource: ", exc,
-                    exc );
+            LOG.atError().withThrowable(exc).log("Unable to close resource");
         }
     }
 
diff --git a/src/java/org/apache/poi/util/NullLogger.java b/src/java/org/apache/poi/util/NullLogger.java
deleted file mode 100644
index 8a9daea..0000000
--- a/src/java/org/apache/poi/util/NullLogger.java
+++ /dev/null
@@ -1,81 +0,0 @@
-/* ====================================================================
-   Licensed to the Apache Software Foundation (ASF) under one or more
-   contributor license agreements.  See the NOTICE file distributed with
-   this work for additional information regarding copyright ownership.
-   The ASF licenses this file to You under the Apache License, Version 2.0
-   (the "License"); you may not use this file except in compliance with
-   the License.  You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
-==================================================================== */
-
-package org.apache.poi.util;
-
-/**
- * An empty-implementation of the {@link POILogger}.
- *
- * This can be used to not log anything, however the suggested approach
- * in production systems is to use the {@link CommonsLogger} and configure
- * proper log-handling via Apache Commons Logging.
- */
-@Internal
-public class NullLogger implements POILogger {
-    @Override
-    public void initialize(final String cat) {
-       // do nothing
-    }
-
-    /**
-     * Log a message
-     *
-     * @param level One of DEBUG, INFO, WARN, ERROR, FATAL
-     * @param obj1 The object to log.
-     */
-
-    @Override
-    public void _log(final int level, final Object obj1) {
-        // do nothing
-    }
-
-    /**
-     * Log a message
-     *
-     * @param level One of DEBUG, INFO, WARN, ERROR, FATAL
-     * @param obj1 The object to log.  This is converted to a string.
-     * @param exception An exception to be logged
-     */
-    @Override
-    public void _log(int level, Object obj1, final Throwable exception) {
-        // do nothing
-    }
-
-    /**
-     * Log a message. Lazily appends Object parameters together.
-     * If the last parameter is a {@link Throwable} it is logged specially.
-     *
-     * @param level One of DEBUG, INFO, WARN, ERROR, FATAL
-     * @param objs the objects to place in the message
-     */
-    @Override
-    public void log(int level, Object... objs) {
-        // do nothing
-    }
-
-
-    /**
-     * Check if a logger is enabled to log at the specified level
-     *
-     * @param level One of DEBUG, INFO, WARN, ERROR, FATAL
-     */
-    @Override
-    public boolean check(final int level) {
-       return false;
-    }
-}
-
diff --git a/src/java/org/apache/poi/util/POILogFactory.java b/src/java/org/apache/poi/util/POILogFactory.java
deleted file mode 100644
index 576ea55..0000000
--- a/src/java/org/apache/poi/util/POILogFactory.java
+++ /dev/null
@@ -1,122 +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.poi.util;
-
-import java.util.HashMap;
-import java.util.Map;
-
-/**
- * Provides logging without clients having to mess with
- * configuration/initialization.
- *
- * @author Andrew C. Oliver (acoliver at apache dot org)
- * @author Marc Johnson (mjohnson at apache dot org)
- * @author Nicola Ken Barozzi (nicolaken at apache.org)
- */
-@Internal
-public final class POILogFactory {
-    /**
-     * Map of POILogger instances, with classes as keys
-     */
-    private static final Map<String,POILogger> _loggers = new HashMap<>();
-
-    /**
-     * A common instance of NullLogger, as it does nothing
-     *  we only need the one
-     */
-    private static final POILogger _nullLogger = new NullLogger();
-    /**
-     * The name of the class to use. Initialised the
-     *  first time we need it
-     */
-    static String _loggerClassName;
-
-    /**
-     * Construct a POILogFactory.
-     */
-    private POILogFactory() {}
-
-    /**
-     * Get a logger, based on a class name
-     *
-     * @param theclass the class whose name defines the log
-     *
-     * @return a POILogger for the specified class
-     */
-    public static POILogger getLogger(final Class<?> theclass) {
-        return getLogger(theclass.getName());
-    }
-
-    /**
-     * Get a logger, based on a String
-     *
-     * @param cat the String that defines the log
-     *
-     * @return a POILogger for the specified class
-     */
-    public static POILogger getLogger(final String cat) {
-        // If we haven't found out what logger to use yet,
-        //  then do so now
-        // Don't look it up until we're first asked, so
-        //  that our users can set the system property
-        //  between class loading and first use
-        if(_loggerClassName == null) {
-        	try {
-        		_loggerClassName = System.getProperty("org.apache.poi.util.POILogger");
-        	} catch(Exception e) {
-                // ignore any exception here
-            }
-
-        	// Use the default logger if none specified,
-        	//  or none could be fetched
-        	if(_loggerClassName == null) {
-                _loggerClassName = _nullLogger.getClass().getName();
-        	}
-        }
-
-        // Short circuit for the null logger, which
-        //  ignores all categories
-        if(_loggerClassName.equals(_nullLogger.getClass().getName())) {
-        	return _nullLogger;
-        }
-
-
-        // Fetch the right logger for them, creating
-        //  it if that's required
-        POILogger logger = _loggers.get(cat);
-        if (logger == null) {
-            try {
-                @SuppressWarnings("unchecked")
-                Class<? extends POILogger> loggerClass =
-                    (Class<? extends POILogger>) Class.forName(_loggerClassName);
-                logger = loggerClass.getConstructor().newInstance();
-                logger.initialize(cat);
-            } catch(Exception e) {
-                // Give up and use the null logger
-                logger = _nullLogger;
-                _loggerClassName = _nullLogger.getClass().getName();
-            }
-
-            // Save for next time
-            _loggers.put(cat, logger);
-        }
-        return logger;
-    }
-}
\ No newline at end of file
diff --git a/src/java/org/apache/poi/util/POILogger.java b/src/java/org/apache/poi/util/POILogger.java
deleted file mode 100644
index da4fbb2..0000000
--- a/src/java/org/apache/poi/util/POILogger.java
+++ /dev/null
@@ -1,128 +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.poi.util;
-
-/**
- * A logger interface that strives to make it as easy as possible for
- * developers to write log calls, while simultaneously making those
- * calls as cheap as possible by performing lazy evaluation of the log
- * message.
- *
- * A logger can be selected via system properties, e.g.
- * <code>
- *     -Dorg.apache.poi.util.POILogger=org.apache.poi.util.SystemOutLogger
- * </code>
- *
- * The following Logger-implementations are provided:
- *
- * <ul>
- *     <li>NullLogger</li>
- *     <li>CommonsLogger</li>
- *     <li>SystemOutLogger</li>
- * </ul>
- */
-@Internal
-public interface POILogger {
-
-    int DEBUG = 1;
-    int INFO  = 3;
-    int WARN  = 5;
-    int ERROR = 7;
-    int FATAL = 9;
-
-    /**
-     * Initialize the Logger - belongs to the SPI, called from the POILogFactory
-     * @param cat the String that defines the log
-     */
-    void initialize(String cat);
-
-    /**
-     * Log a message - belongs to the SPI, usually not called from user code
-     *
-     * @param level One of DEBUG, INFO, WARN, ERROR, FATAL
-     * @param obj1 The object to log.  This is converted to a string.
-     */
-    @Internal
-    void _log(int level, Object obj1);
-
-    /**
-     * Log a message - belongs to the SPI, usually not called from user code
-     *
-     * @param level One of DEBUG, INFO, WARN, ERROR, FATAL
-     * @param obj1 The object to log.  This is converted to a string.
-     * @param exception An exception to be logged
-     */
-    @Internal
-    void _log(int level, Object obj1, final Throwable exception);
-
-
-    /**
-     * Check if a logger is enabled to log at the specified level
-     * This allows code to avoid building strings or evaluating functions in
-     * the arguments to log.
-     *
-     * An example:
-     * <code><pre>
-     * if (logger.check(POILogger.INFO)) {
-     *     logger.log(POILogger.INFO, "Avoid concatenating ", " strings and evaluating ", functions());
-     * }
-     * </pre></code>
-     *
-     * @param level One of DEBUG, INFO, WARN, ERROR, FATAL
-     */
-    boolean check(int level);
-
-   /**
-     * Log a message. Lazily appends Object parameters together.
-     * If the last parameter is a {@link Throwable} it is logged specially.
-     *
-     * @param level One of DEBUG, INFO, WARN, ERROR, FATAL
-     * @param objs the objects to place in the message
-     */
-    default void log(int level, Object... objs) {
-        if (!check(level)) return;
-        Throwable lastEx = null;
-        String msg;
-        if (objs.length == 0) {
-            msg = "";
-        } else if (objs.length == 1) {
-            if (objs[0] instanceof Throwable) {
-                lastEx = (Throwable)objs[0];
-            }
-            msg = objs[0].toString();
-        } else {
-            StringBuilder sb = new StringBuilder(32);
-            for (int i=0; i<objs.length; i++) {
-                if (i == objs.length-1 && objs[i] instanceof Throwable) {
-                    lastEx = (Throwable)objs[i];
-                } else {
-                    sb.append(objs[i]);
-                }
-            }
-            msg = sb.toString();
-        }
-        // log forging escape
-        msg = msg.replaceAll("[\r\n]+", " ");
-
-        if (lastEx == null) {
-            _log(level, msg);
-        } else {
-            _log(level, msg, lastEx);
-        }
-    }
-}
diff --git a/src/java/org/apache/poi/util/SLF4JLogger.java b/src/java/org/apache/poi/util/SLF4JLogger.java
deleted file mode 100644
index 236fc2c..0000000
--- a/src/java/org/apache/poi/util/SLF4JLogger.java
+++ /dev/null
@@ -1,157 +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.poi.util;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- * An implementation of the {@link POILogger} using the
- * SLF4J framework. Which itself can be configured to
- * send log to various different log frameworks and even allows to create
- * a small wrapper for custom log frameworks.
- */
-public class SLF4JLogger implements POILogger
-{
-    private Logger log;
-
-    @Override
-    public void initialize(final String cat) {
-        this.log = LoggerFactory.getLogger(cat);
-    }
-
-    /**
-     * Log a message
-     *
-     * @param level One of DEBUG, INFO, WARN, ERROR, FATAL
-     * @param obj1 The object to log.
-     */
-    @Override
-    public void _log(final int level, final Object obj1) {
-        switch (level) {
-            case FATAL:
-            case ERROR:
-                if (log.isErrorEnabled()) {
-                    log.error(obj1.toString());
-                }
-                break;
-            case WARN:
-                if (log.isWarnEnabled()) {
-                    log.warn(obj1.toString());
-                }
-                break;
-            case INFO:
-                if (log.isInfoEnabled()) {
-                    log.info(obj1.toString());
-                }
-                break;
-            case DEBUG:
-                if (log.isDebugEnabled()) {
-                    log.debug(obj1.toString());
-                }
-                break;
-            default:
-                if (log.isTraceEnabled()) {
-                    log.trace(obj1.toString());
-                }
-                break;
-        }
-    }
-
-    /**
-     * Log a message
-     *
-     * @param level One of DEBUG, INFO, WARN, ERROR, FATAL
-     * @param obj1 The object to log.  This is converted to a string.
-     * @param exception An exception to be logged
-     */
-    @Override
-    public void _log(final int level, final Object obj1, final Throwable exception) {
-        switch (level) {
-            case FATAL:
-            case ERROR:
-                if (log.isErrorEnabled()) {
-                    if (obj1 != null) {
-                        log.error(obj1.toString(), exception);
-                    } else {
-                        log.error(exception.toString(), exception);
-                    }
-                }
-                break;
-            case WARN:
-                if (log.isWarnEnabled()) {
-                    if (obj1 != null) {
-                        log.warn(obj1.toString(), exception);
-                    } else {
-                        log.warn(exception.toString(), exception);
-                    }
-                }
-                break;
-            case INFO:
-                if (log.isInfoEnabled()) {
-                    if (obj1 != null) {
-                        log.info(obj1.toString(), exception);
-                    } else {
-                        log.info(exception.toString(), exception);
-                    }
-                }
-                break;
-            case DEBUG:
-                if (log.isDebugEnabled()) {
-                    if (obj1 != null) {
-                        log.debug(obj1.toString(), exception);
-                    } else {
-                        log.debug(exception.toString(), exception);
-                    }
-                }
-                break;
-            default:
-                if (log.isTraceEnabled()) {
-                    if (obj1 != null) {
-                        log.trace(obj1.toString(), exception);
-                    } else {
-                        log.trace(exception.toString(), exception);
-                    }
-                }
-                break;
-        }
-    }
-
-    /**
-     * Check if a logger is enabled to log at the specified level
-     *
-     * @param level One of DEBUG, INFO, WARN, ERROR, FATAL
-     */
-    @Override
-    public boolean check(final int level)
-    {
-        switch (level) {
-            case FATAL:
-            case ERROR:
-                return log.isErrorEnabled();
-            case WARN:
-                return log.isWarnEnabled();
-            case INFO:
-                return log.isInfoEnabled();
-            case DEBUG:
-                return log.isDebugEnabled();
-            default:
-                return false;
-        }
-    }
-}
-
diff --git a/src/java/org/apache/poi/util/SystemOutLogger.java b/src/java/org/apache/poi/util/SystemOutLogger.java
deleted file mode 100644
index cc414f7..0000000
--- a/src/java/org/apache/poi/util/SystemOutLogger.java
+++ /dev/null
@@ -1,96 +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.poi.util;
-
-/**
- * An implementation of the {@link POILogger} which uses System.out.println.
- *
- * This can be used to provide simply output from applications, however the
- * suggested approach in production systems is to use the {@link CommonsLogger}
- * and configure proper log-handling via Apache Commons Logging.
- */
-public class SystemOutLogger implements POILogger {
-    /**
-     * Short strings for numeric log level. Use level as array index.
-     */
-    private static final String LEVEL_STRINGS_SHORT = "?D?I?W?E?F?";
-
-    private String _cat;
-
-    @Override
-    public void initialize(final String cat) {
-       this._cat=cat;
-    }
-
-    /**
-     * Log a message
-     *
-     * @param level One of DEBUG, INFO, WARN, ERROR, FATAL
-     * @param obj1 The object to log.
-     */
-    @Override
-    public void _log(final int level, final Object obj1) {
-    	_log(level, obj1, null);
-    }
-
-    /**
-     * Log a message
-     *
-     * @param level One of DEBUG, INFO, WARN, ERROR, FATAL
-     * @param obj1 The object to log.  This is converted to a string.
-     * @param exception An exception to be logged
-     */
-    @Override
-    @SuppressForbidden("uses printStackTrace")
-    public void _log(final int level, final Object obj1, final Throwable exception) {
-        if (!check(level)) {
-            return;
-        }
-        System.out.print("[");
-        System.out.print(_cat);
-        System.out.print("]");
-        System.out.print(LEVEL_STRINGS_SHORT.charAt(Math.min(LEVEL_STRINGS_SHORT.length()-1, level)));
-        System.out.print(" ");
-        System.out.println(obj1);
-        if (exception != null) {
-            exception.printStackTrace(System.out);
-        }
-    }
-
-    /**
-     * Check if a logger is enabled to log at the specified level
-     *
-     * @param level One of DEBUG, INFO, WARN, ERROR, FATAL
-     * @see #DEBUG
-     * @see #INFO
-     * @see #WARN
-     * @see #ERROR
-     * @see #FATAL
-     */
-    @Override
-    public boolean check(final int level) {
-        int currentLevel;
-        try {
-            currentLevel = Integer.parseInt(System.getProperty("poi.log.level", WARN + ""));
-        } catch (SecurityException e) {
-            currentLevel = POILogger.DEBUG;
-        }
-
-        return level >= currentLevel;
-    }
-}
-
diff --git a/src/java/org/apache/poi/util/XMLHelper.java b/src/java/org/apache/poi/util/XMLHelper.java
index 72a7633..e27c976 100644
--- a/src/java/org/apache/poi/util/XMLHelper.java
+++ b/src/java/org/apache/poi/util/XMLHelper.java
@@ -46,6 +46,9 @@
 import javax.xml.transform.TransformerFactory;
 import javax.xml.validation.SchemaFactory;
 
+import org.apache.logging.log4j.Level;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.xml.sax.ErrorHandler;
 import org.xml.sax.InputSource;
 import org.xml.sax.SAXException;
@@ -74,7 +77,7 @@
     };
 
 
-    private static final POILogger LOG = POILogFactory.getLogger(XMLHelper.class);
+    private static final Logger LOG = LogManager.getLogger(XMLHelper.class);
     private static long lastLog;
 
     // DocumentBuilderFactory.newDocumentBuilder is thread-safe
@@ -290,7 +293,7 @@
 
     private static void logThrowable(Throwable t, String message, String name) {
         if (System.currentTimeMillis() > lastLog + TimeUnit.MINUTES.toMillis(5)) {
-            LOG.log(POILogger.WARN, message + " [log suppressed for 5 minutes]", name, t);
+            LOG.atWarn().withThrowable(t).log("{} [log suppressed for 5 minutes]{}", message, name);
             lastLog = System.currentTimeMillis();
         }
     }
@@ -298,22 +301,22 @@
     private static class DocHelperErrorHandler implements ErrorHandler {
 
         public void warning(SAXParseException exception) {
-            printError(POILogger.WARN, exception);
+            printError(Level.WARN, exception);
         }
 
         public void error(SAXParseException exception) {
-            printError(POILogger.ERROR, exception);
+            printError(Level.ERROR, exception);
         }
 
         public void fatalError(SAXParseException exception) throws SAXException {
-            printError(POILogger.FATAL, exception);
+            printError(Level.FATAL, exception);
             throw exception;
         }
 
         /**
          * Prints the error message.
          */
-        private void printError(int type, SAXParseException ex) {
+        private void printError(Level type, SAXParseException ex) {
             String systemId = ex.getSystemId();
             if (systemId != null) {
                 int index = systemId.lastIndexOf('/');
@@ -326,7 +329,7 @@
                     ':' + ex.getColumnNumber() +
                     ':' + ex.getMessage();
 
-            LOG.log(type, message, ex);
+            LOG.atLevel(type).withThrowable(ex).log(message);
         }
     }
 
diff --git a/src/multimodule/ooxml/java9/module-info.class b/src/multimodule/ooxml/java9/module-info.class
index 98795b8..9d0a03b 100644
--- a/src/multimodule/ooxml/java9/module-info.class
+++ b/src/multimodule/ooxml/java9/module-info.class
Binary files differ
diff --git a/src/multimodule/ooxml/java9/module-info.java b/src/multimodule/ooxml/java9/module-info.java
index 9067580..d8893df 100644
--- a/src/multimodule/ooxml/java9/module-info.java
+++ b/src/multimodule/ooxml/java9/module-info.java
@@ -23,7 +23,7 @@
     requires org.apache.commons.codec;
     requires commons.math3;
     requires SparseBitSet;
-    requires org.slf4j;
+    requires org.apache.logging.log4j;
     requires java.logging;
     requires java.desktop;
     requires java.security.jgss;
diff --git a/src/multimodule/ooxml/test9/module-info.class b/src/multimodule/ooxml/test9/module-info.class
index a9ad223..db5f9a3 100644
--- a/src/multimodule/ooxml/test9/module-info.class
+++ b/src/multimodule/ooxml/test9/module-info.class
Binary files differ
diff --git a/src/multimodule/ooxml/test9/module-info.java b/src/multimodule/ooxml/test9/module-info.java
index 447384a..09195b1 100644
--- a/src/multimodule/ooxml/test9/module-info.java
+++ b/src/multimodule/ooxml/test9/module-info.java
@@ -23,7 +23,7 @@
     requires org.apache.commons.codec;
     requires commons.math3;
     requires SparseBitSet;
-    requires org.slf4j;
+    requires org.apache.logging.log4j;
     requires java.logging;
     requires java.desktop;
     requires java.security.jgss;
diff --git a/src/multimodule/poi/java9/module-info.class b/src/multimodule/poi/java9/module-info.class
index 5a26949..a34febe 100644
--- a/src/multimodule/poi/java9/module-info.class
+++ b/src/multimodule/poi/java9/module-info.class
Binary files differ
diff --git a/src/multimodule/poi/java9/module-info.java b/src/multimodule/poi/java9/module-info.java
index ed577f5..a941092 100644
--- a/src/multimodule/poi/java9/module-info.java
+++ b/src/multimodule/poi/java9/module-info.java
@@ -20,7 +20,7 @@
     requires org.apache.commons.codec;
     requires commons.math3;
     requires SparseBitSet;
-    requires org.slf4j;
+    requires org.apache.logging.log4j;
     requires java.logging;
     requires java.desktop;
 
diff --git a/src/multimodule/poi/test9/module-info.class b/src/multimodule/poi/test9/module-info.class
index 99b70e7..31c2434 100644
--- a/src/multimodule/poi/test9/module-info.class
+++ b/src/multimodule/poi/test9/module-info.class
Binary files differ
diff --git a/src/multimodule/poi/test9/module-info.java b/src/multimodule/poi/test9/module-info.java
index 271ab81..58ac222 100644
--- a/src/multimodule/poi/test9/module-info.java
+++ b/src/multimodule/poi/test9/module-info.java
@@ -20,7 +20,7 @@
     requires org.apache.commons.codec;
     requires commons.math3;
     requires SparseBitSet;
-    requires org.slf4j;
+    requires org.apache.logging.log4j;
     requires java.logging;
     requires java.desktop;
 
diff --git a/src/ooxml/java/org/apache/poi/ooxml/POIXMLDocumentPart.java b/src/ooxml/java/org/apache/poi/ooxml/POIXMLDocumentPart.java
index e1291fe..4696e71 100644
--- a/src/ooxml/java/org/apache/poi/ooxml/POIXMLDocumentPart.java
+++ b/src/ooxml/java/org/apache/poi/ooxml/POIXMLDocumentPart.java
@@ -25,6 +25,8 @@
 import java.util.Map;
 import java.util.Set;
 
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
 import org.apache.poi.openxml4j.exceptions.OpenXML4JException;
 import org.apache.poi.openxml4j.exceptions.PartAlreadyExistsException;
@@ -38,21 +40,20 @@
 import org.apache.poi.openxml4j.opc.TargetMode;
 import org.apache.poi.util.IOUtils;
 import org.apache.poi.util.Internal;
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
 import org.apache.poi.xddf.usermodel.chart.XDDFChart;
 import org.apache.poi.xssf.usermodel.XSSFRelation;
 import org.apache.poi.xssf.usermodel.XSSFWorkbook;
+import org.apache.poi.xwpf.usermodel.XWPFDocument;
 import org.apache.poi.xwpf.usermodel.XWPFRelation;
 
 /**
  * Represents an entry of a OOXML package.
  * <p>
- * Each POIXMLDocumentPart keeps a reference to the underlying a {@link org.apache.poi.openxml4j.opc.PackagePart}.
+ * Each POIXMLDocumentPart keeps a reference to the underlying a {@link PackagePart}.
  * </p>
  */
 public class POIXMLDocumentPart {
-    private static final POILogger LOG = POILogFactory.getLogger(POIXMLDocumentPart.class);
+    private static final Logger LOG = LogManager.getLogger(POIXMLDocumentPart.class);
 
     private String coreDocumentRel = PackageRelationshipTypes.CORE_DOCUMENT;
     private PackagePart packagePart;
@@ -161,10 +162,10 @@
 
     /**
      * Creates an POIXMLDocumentPart representing the given package part and relationship.
-     * Called by {@link #read(POIXMLFactory, java.util.Map)} when reading in an existing file.
+     * Called by {@link #read(POIXMLFactory, Map)} when reading in an existing file.
      *
      * @param part - The package part that holds xml data representing this sheet.
-     * @see #read(POIXMLFactory, java.util.Map)
+     * @see #read(POIXMLFactory, Map)
      * @since POI 3.14-Beta1
      */
     public POIXMLDocumentPart(PackagePart part) {
@@ -173,11 +174,11 @@
 
     /**
      * Creates an POIXMLDocumentPart representing the given package part, relationship and parent
-     * Called by {@link #read(POIXMLFactory, java.util.Map)} when reading in an existing file.
+     * Called by {@link #read(POIXMLFactory, Map)} when reading in an existing file.
      *
      * @param parent - Parent part
      * @param part   - The package part that holds xml data representing this sheet.
-     * @see #read(POIXMLFactory, java.util.Map)
+     * @see #read(POIXMLFactory, Map)
      * @since POI 3.14-Beta1
      */
     public POIXMLDocumentPart(POIXMLDocumentPart parent, PackagePart part) {
@@ -619,8 +620,7 @@
         PackagePart pp = getPackagePart();
 
         if (pp.getContentType().equals(XWPFRelation.GLOSSARY_DOCUMENT.getContentType())) {
-            LOG.log(POILogger.WARN,
-                    "POI does not currently support template.main+xml (glossary) parts.  " +
+            LOG.atWarn().log("POI does not currently support template.main+xml (glossary) parts.  " +
                     "Skipping this part for now.");
             return;
         }
@@ -651,7 +651,7 @@
 
                 final PackagePart p = packagePart.getPackage().getPart(relName);
                 if (p == null) {
-                    LOG.log(POILogger.ERROR, "Skipped invalid entry ", rel.getTargetURI());
+                    LOG.atError().log("Skipped invalid entry {}", rel.getTargetURI());
                     continue;
                 }
 
@@ -721,7 +721,7 @@
      * Internal method, do not use!
      * <p>
      * This method only exists to allow access to protected {@link POIXMLDocumentPart#onDocumentRead()}
-     * from {@link org.apache.poi.xwpf.usermodel.XWPFDocument} without reflection. It should be removed.
+     * from {@link XWPFDocument} without reflection. It should be removed.
      *
      * @param part the part which is to be read
      * @throws IOException if the part can't be read
diff --git a/src/ooxml/java/org/apache/poi/ooxml/POIXMLFactory.java b/src/ooxml/java/org/apache/poi/ooxml/POIXMLFactory.java
index b839e0f..0e91da3 100644
--- a/src/ooxml/java/org/apache/poi/ooxml/POIXMLFactory.java
+++ b/src/ooxml/java/org/apache/poi/ooxml/POIXMLFactory.java
@@ -18,20 +18,20 @@
 
 import java.io.IOException;
 
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.apache.poi.ooxml.POIXMLRelation.PackagePartConstructor;
 import org.apache.poi.ooxml.POIXMLRelation.ParentPartConstructor;
 import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
 import org.apache.poi.openxml4j.opc.PackagePart;
 import org.apache.poi.openxml4j.opc.PackageRelationship;
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
 import org.apache.xmlbeans.XmlException;
 
 /**
  * Defines a factory API that enables sub-classes to create instances of <code>POIXMLDocumentPart</code>
  */
 public abstract class POIXMLFactory {
-    private static final POILogger LOGGER = POILogFactory.getLogger(POIXMLFactory.class);
+    private static final Logger LOGGER = LogManager.getLogger(POIXMLFactory.class);
 
     /**
      * Create a POIXMLDocumentPart from existing package part and relation. This method is called
@@ -62,7 +62,7 @@
                 }
             }
 
-            LOGGER.log(POILogger.DEBUG, "using default POIXMLDocumentPart for ", rel.getRelationshipType());
+            LOGGER.atDebug().log("using default POIXMLDocumentPart for {}", rel.getRelationshipType());
             return new POIXMLDocumentPart(parent, part);
         } catch (IOException | XmlException e) {
             throw new POIXMLException(e.getMessage(), e);
diff --git a/src/ooxml/java/org/apache/poi/ooxml/POIXMLRelation.java b/src/ooxml/java/org/apache/poi/ooxml/POIXMLRelation.java
index ca08b55..5bf576d 100644
--- a/src/ooxml/java/org/apache/poi/ooxml/POIXMLRelation.java
+++ b/src/ooxml/java/org/apache/poi/ooxml/POIXMLRelation.java
@@ -20,6 +20,8 @@
 import java.io.InputStream;
 import java.util.Iterator;
 
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
 import org.apache.poi.openxml4j.opc.PackagePart;
 import org.apache.poi.openxml4j.opc.PackagePartName;
@@ -27,8 +29,6 @@
 import org.apache.poi.openxml4j.opc.PackageRelationshipCollection;
 import org.apache.poi.openxml4j.opc.PackagingURIHelper;
 import org.apache.poi.util.Internal;
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
 import org.apache.xmlbeans.XmlException;
 
 /**
@@ -51,7 +51,7 @@
         POIXMLDocumentPart init(POIXMLDocumentPart parent, PackagePart part) throws IOException, XmlException;
     }
 
-    private static final POILogger log = POILogFactory.getLogger(POIXMLRelation.class);
+    private static final Logger LOGGER = LogManager.getLogger(POIXMLRelation.class);
 
     /**
      * Describes the content stored in a part.
@@ -207,7 +207,7 @@
             PackagePart part = corePart.getPackage().getPart(relName);
             return part.getInputStream();
         }
-        log.log(POILogger.WARN, "No part " + getDefaultFileName() + " found");
+        LOGGER.atWarn().log("No part {} found", getDefaultFileName());
         return null;
     }
 }
diff --git a/src/ooxml/java/org/apache/poi/ooxml/util/XPathHelper.java b/src/ooxml/java/org/apache/poi/ooxml/util/XPathHelper.java
index cd4b25d..6677f01 100644
--- a/src/ooxml/java/org/apache/poi/ooxml/util/XPathHelper.java
+++ b/src/ooxml/java/org/apache/poi/ooxml/util/XPathHelper.java
@@ -24,9 +24,9 @@
 import javax.xml.xpath.XPathFactory;
 
 import com.microsoft.schemas.compatibility.AlternateContentDocument;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.apache.poi.util.Internal;
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
 import org.apache.poi.xslf.usermodel.XSLFShape;
 import org.apache.xmlbeans.XmlCursor;
 import org.apache.xmlbeans.XmlException;
@@ -34,7 +34,7 @@
 import org.apache.xmlbeans.impl.values.XmlAnyTypeImpl;
 
 public final class XPathHelper {
-    private static final POILogger LOG = POILogFactory.getLogger(XPathHelper.class);
+    private static final Logger LOG = LogManager.getLogger(XPathHelper.class);
 
     private static final String OSGI_ERROR =
         "Schemas (*.xsb) for <CLASS> can't be loaded - usually this happens when OSGI " +
@@ -62,9 +62,9 @@
         try {
             xpf.setFeature(feature, enabled);
         } catch (Exception e) {
-            LOG.log(POILogger.WARN, "XPathFactory Feature unsupported", feature, e);
+            LOG.atWarn().withThrowable(e).log("XPathFactory Feature ({}) unsupported", feature);
         } catch (AbstractMethodError ame) {
-            LOG.log(POILogger.WARN, "Cannot set XPathFactory feature because outdated XML parser in classpath", feature, ame);
+            LOG.atWarn().withThrowable(ame).log("Cannot set XPathFactory feature ({}) because outdated XML parser in classpath", feature);
         }
     }
 
diff --git a/src/ooxml/java/org/apache/poi/openxml4j/opc/OPCPackage.java b/src/ooxml/java/org/apache/poi/openxml4j/opc/OPCPackage.java
index 203d5c1..fe64858 100644
--- a/src/ooxml/java/org/apache/poi/openxml4j/opc/OPCPackage.java
+++ b/src/ooxml/java/org/apache/poi/openxml4j/opc/OPCPackage.java
@@ -42,6 +42,8 @@
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
 import org.apache.poi.openxml4j.exceptions.InvalidOperationException;
 import org.apache.poi.openxml4j.exceptions.OpenXML4JRuntimeException;
@@ -59,8 +61,6 @@
 import org.apache.poi.openxml4j.util.ZipEntrySource;
 import org.apache.poi.util.IOUtils;
 import org.apache.poi.util.NotImplemented;
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
 
 /**
  * Represents a container that can store multiple data objects.
@@ -70,7 +70,7 @@
 	/**
 	 * Logger.
 	 */
-    private static final POILogger LOG = POILogFactory.getLogger(OPCPackage.class);
+    private static final Logger LOG = LogManager.getLogger(OPCPackage.class);
 
 	/**
 	 * Default package access.
@@ -442,14 +442,12 @@
 		}
 
 		if (this.packageAccess == PackageAccess.READ) {
-			LOG.log(POILogger.WARN,
-			        "The close() method is intended to SAVE a package. This package is open in READ ONLY mode, use the revert() method instead !");
+			LOG.atWarn().log("The close() method is intended to SAVE a package. This package is open in READ ONLY mode, use the revert() method instead!");
 			revert();
 			return;
 		}
 		if (this.contentTypeManager == null) {
-		    LOG.log(POILogger.WARN,
-		            "Unable to call close() on a package that hasn't been fully opened yet");
+		    LOG.atWarn().log("Unable to call close() on a package that hasn't been fully opened yet");
 			revert();
 		    return;
 		}
@@ -559,7 +557,7 @@
      *
      * @throws InvalidOperationException
      *             Throws if a writing operation is done on a read only package.
-     * @see org.apache.poi.openxml4j.opc.PackageAccess
+     * @see PackageAccess
      */
     void throwExceptionIfReadOnly() throws InvalidOperationException {
         if (packageAccess == PackageAccess.READ) {
@@ -574,7 +572,7 @@
 	 * right.
 	 *
 	 * @throws InvalidOperationException if a read operation is done on a write only package.
-	 * @see org.apache.poi.openxml4j.opc.PackageAccess
+	 * @see PackageAccess
 	 */
 	void throwExceptionIfWriteOnly() throws InvalidOperationException {
 		if (packageAccess == PackageAccess.WRITE) {
@@ -748,7 +746,7 @@
 					if (!hasCorePropertiesPart) {
 						hasCorePropertiesPart = true;
 					} else {
-					   LOG.log(POILogger.WARN, "OPC Compliance error [M4.1]: " +
+					   LOG.atWarn().log("OPC Compliance error [M4.1]: " +
 					   		"there is more than one core properties relationship in the package! " +
 					   		"POI will use only the first, but other software may reject this file.");
 					}
@@ -772,9 +770,7 @@
 							needCorePropertiesPart = false;
 						}
 					} catch (IOException ioe) {
-						LOG.log(POILogger.WARN, "Unmarshall operation : IOException for "
-								+ part._partName);
-						continue;
+						LOG.atWarn().log("Unmarshall operation : IOException for {}", part._partName);
 					} catch (InvalidOperationException invoe) {
 						throw new InvalidFormatException(invoe.getMessage(), invoe);
 					}
@@ -1005,9 +1001,7 @@
 			try {
 				sourcePartName = PackagingURIHelper.createPartName(sourceURI);
 			} catch (InvalidFormatException e) {
-				LOG
-						.log(POILogger.ERROR, "Part name URI '", sourceURI,
-								"' is not valid ! This message is not intended to be displayed !");
+				LOG.atError().log("Part name URI '{}' is not valid! This message is not intended to be displayed!", sourceURI);
 				return;
 			}
 			if (sourcePartName.getURI().equals(
@@ -1109,10 +1103,7 @@
 				this.deletePartRecursive(targetPartName);
 			}
 		} catch (InvalidFormatException e) {
-			LOG.log(POILogger.WARN, "An exception occurs while deleting part '"
-					+ partName.getName()
-					+ "'. Some parts may remain in the package. - "
-					+ e.getMessage());
+			LOG.atWarn().withThrowable(e).log("An exception occurs while deleting part '{}'. Some parts may remain in the package.", partName.getName());
 			return;
 		}
 		// Remove the relationships part
@@ -1226,8 +1217,8 @@
 	 * @param relationshipType
 	 *            Type of relationship.
 	 * @return The newly created and added relationship
-	 * @see org.apache.poi.openxml4j.opc.RelationshipSource#addExternalRelationship(java.lang.String,
-	 *      java.lang.String)
+	 * @see RelationshipSource#addExternalRelationship(String,
+	 *      String)
 	 */
 	@Override
     public PackageRelationship addExternalRelationship(String target,
@@ -1249,8 +1240,8 @@
 	 * @param id
 	 *            Relationship unique id.
 	 * @return The newly created and added relationship
-	 * @see org.apache.poi.openxml4j.opc.RelationshipSource#addExternalRelationship(java.lang.String,
-	 *      java.lang.String)
+	 * @see RelationshipSource#addExternalRelationship(String,
+	 *      String)
 	 */
 	@Override
     public PackageRelationship addExternalRelationship(String target,
@@ -1357,7 +1348,7 @@
 	}
 
 	/**
-	 * @see org.apache.poi.openxml4j.opc.RelationshipSource#getRelationship(java.lang.String)
+	 * @see RelationshipSource#getRelationship(String)
 	 */
 	@Override
     public PackageRelationship getRelationship(String id) {
@@ -1365,7 +1356,7 @@
 	}
 
 	/**
-	 * @see org.apache.poi.openxml4j.opc.RelationshipSource#hasRelationships()
+	 * @see RelationshipSource#hasRelationships()
 	 */
 	@Override
     public boolean hasRelationships() {
@@ -1373,7 +1364,7 @@
 	}
 
 	/**
-	 * @see org.apache.poi.openxml4j.opc.RelationshipSource#isRelationshipExists(org.apache.poi.openxml4j.opc.PackageRelationship)
+	 * @see RelationshipSource#isRelationshipExists(PackageRelationship)
 	 */
 	@Override
     public boolean isRelationshipExists(PackageRelationship rel) {
@@ -1397,8 +1388,7 @@
 		try {
 			partMarshallers.put(new ContentType(contentType), marshaller);
 		} catch (InvalidFormatException e) {
-			LOG.log(POILogger.WARN, "The specified content type is not valid: '"
-					+ e.getMessage() + "'. The marshaller will not be added !");
+			LOG.atWarn().log("The specified content type is not valid: '{}'. The marshaller will not be added !", e.getMessage());
 		}
 	}
 
@@ -1415,9 +1405,7 @@
 		try {
 			partUnmarshallers.put(new ContentType(contentType), unmarshaller);
 		} catch (InvalidFormatException e) {
-			LOG.log(POILogger.WARN, "The specified content type is not valid: '"
-					+ e.getMessage()
-					+ "'. The unmarshaller will not be added !");
+			LOG.atWarn().log("The specified content type is not valid: '{}'. The unmarshaller will not be added !", e.getMessage());
 		}
 	}
 
diff --git a/src/ooxml/java/org/apache/poi/openxml4j/opc/PackagePart.java b/src/ooxml/java/org/apache/poi/openxml4j/opc/PackagePart.java
index 4956032..81519ff 100644
--- a/src/ooxml/java/org/apache/poi/openxml4j/opc/PackagePart.java
+++ b/src/ooxml/java/org/apache/poi/openxml4j/opc/PackagePart.java
@@ -699,7 +699,7 @@
      * @param zos
      *            Output stream to save this part.
      * @return true if the content has been successfully stored, false otherwise.
-     *         More information about errors may be logged via {@link org.apache.poi.util.POILogger}
+     *         More information about errors may be logged via Log4j 2.
      * @throws OpenXML4JException
      *             If any exception occur.
      */
@@ -711,7 +711,7 @@
      * @param ios
      *            The input stream of the content to load.
      * @return true if the content has been successfully loaded, false otherwise.
-     *         More information about errors may be logged via {@link org.apache.poi.util.POILogger}
+     *         More information about errors may be logged via Log4j 2.
      * @throws InvalidFormatException
      *             Throws if the content format is invalid.
      */
diff --git a/src/ooxml/java/org/apache/poi/openxml4j/opc/PackageRelationshipCollection.java b/src/ooxml/java/org/apache/poi/openxml4j/opc/PackageRelationshipCollection.java
index 53fb372..07f8b98 100644
--- a/src/ooxml/java/org/apache/poi/openxml4j/opc/PackageRelationshipCollection.java
+++ b/src/ooxml/java/org/apache/poi/openxml4j/opc/PackageRelationshipCollection.java
@@ -20,11 +20,11 @@
 import java.net.URISyntaxException;
 import java.util.*;
 
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
 import org.apache.poi.openxml4j.exceptions.InvalidOperationException;
 import org.apache.poi.ooxml.util.DocumentHelper;
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
 import org.w3c.dom.Attr;
 import org.w3c.dom.Document;
 import org.w3c.dom.Element;
@@ -39,7 +39,7 @@
  */
 public final class PackageRelationshipCollection implements Iterable<PackageRelationship> {
 
-    private static final POILogger LOG = POILogFactory.getLogger(PackageRelationshipCollection.class);
+    private static final Logger LOG = LogManager.getLogger(PackageRelationshipCollection.class);
 
     /**
      * Package relationships ordered by ID.
@@ -300,7 +300,7 @@
     public void parseRelationshipsPart(PackagePart relPart)
             throws InvalidFormatException {
         try {
-            LOG.log(POILogger.DEBUG, "Parsing relationship: ", relPart.getPartName());
+            LOG.atDebug().log("Parsing relationship: {}", relPart.getPartName());
             Document xmlRelationshipsDoc = DocumentHelper.readDocument(relPart.getInputStream());
 
             // Browse default types
@@ -348,8 +348,7 @@
                     // package
                     target = PackagingURIHelper.toURI(value);
                 } catch (URISyntaxException e) {
-                    LOG.log(POILogger.ERROR, "Cannot convert ", value,
-                            " in a valid relationship URI-> dummy-URI used", e);
+                    LOG.atError().withThrowable(e).log("Cannot convert {} in a valid relationship URI-> dummy-URI used", value);
                 }
                 addRelationship(target, targetMode, type, id);
             }
diff --git a/src/ooxml/java/org/apache/poi/openxml4j/opc/PackagingURIHelper.java b/src/ooxml/java/org/apache/poi/openxml4j/opc/PackagingURIHelper.java
index 32f8950..bd1bce1 100644
--- a/src/ooxml/java/org/apache/poi/openxml4j/opc/PackagingURIHelper.java
+++ b/src/ooxml/java/org/apache/poi/openxml4j/opc/PackagingURIHelper.java
@@ -23,10 +23,10 @@
 import java.nio.charset.StandardCharsets;
 import java.util.regex.Pattern;
 
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
 import org.apache.poi.openxml4j.exceptions.InvalidOperationException;
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
 
 /**
  * Helper for part and pack URI.
@@ -38,7 +38,7 @@
     // FIXME: this class implements a lot of path joining and splitting logic that
     // is already implemented in java.nio.file.Path.
     // This class should heavily leverage Java library code to reduce the number of lines of code that POI has to maintain and test
-    private static final POILogger LOG = POILogFactory.getLogger(PackagingURIHelper.class);
+    private static final Logger LOG = LogManager.getLogger(PackagingURIHelper.class);
 
     /**
      * Package root URI.
@@ -290,7 +290,7 @@
                 try {
                     targetURI = new URI(path.substring(1));
                 } catch (Exception e) {
-                    LOG.log(POILogger.WARN, e);
+                    LOG.atWarn().withThrowable(e).log("Failed to relativize");
                     return null;
                 }
             }
@@ -328,7 +328,7 @@
             try {
                 return new URI(retVal.toString());
             } catch (Exception e) {
-                LOG.log(POILogger.WARN, e);
+                LOG.atWarn().withThrowable(e).log("Failed to relativize");
                 return null;
             }
         }
@@ -377,7 +377,7 @@
         try {
             return new URI(retVal.toString());
         } catch (Exception e) {
-            LOG.log(POILogger.WARN, e);
+            LOG.atWarn().withThrowable(e).log("Failed to relativize");
             return null;
         }
     }
@@ -661,7 +661,7 @@
     }
 
     /**
-     * Convert a string to {@link java.net.URI}
+     * Convert a string to {@link URI}
      *
      * If  part name is not a valid URI, it is resolved as follows:
      * <p>
diff --git a/src/ooxml/java/org/apache/poi/openxml4j/opc/ZipPackage.java b/src/ooxml/java/org/apache/poi/openxml4j/opc/ZipPackage.java
index b65996b..67e7c44 100644
--- a/src/ooxml/java/org/apache/poi/openxml4j/opc/ZipPackage.java
+++ b/src/ooxml/java/org/apache/poi/openxml4j/opc/ZipPackage.java
@@ -33,6 +33,9 @@
 import org.apache.commons.compress.archivers.zip.ZipArchiveEntry;
 import org.apache.commons.compress.archivers.zip.ZipArchiveOutputStream;
 import org.apache.commons.compress.archivers.zip.ZipFile;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+import org.apache.logging.log4j.message.SimpleMessage;
 import org.apache.poi.UnsupportedFileFormatException;
 import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
 import org.apache.poi.openxml4j.exceptions.InvalidOperationException;
@@ -52,8 +55,6 @@
 import org.apache.poi.openxml4j.util.ZipFileZipEntrySource;
 import org.apache.poi.openxml4j.util.ZipInputStreamZipEntrySource;
 import org.apache.poi.util.IOUtils;
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
 import org.apache.poi.util.TempFile;
 
 /**
@@ -63,7 +64,7 @@
     private static final String MIMETYPE = "mimetype";
     private static final String SETTINGS_XML = "settings.xml";
 
-    private static final POILogger LOG = POILogFactory.getLogger(ZipPackage.class);
+    private static final Logger LOG = LogManager.getLogger(ZipPackage.class);
 
     /**
      * Zip archive, as either a file on disk,
@@ -81,7 +82,7 @@
         try {
             this.contentTypeManager = new ZipContentTypeManager(null, this);
         } catch (InvalidFormatException e) {
-            LOG.log(POILogger.WARN,"Could not parse ZipPackage", e);
+            LOG.atWarn().withThrowable(e).log("Could not parse ZipPackage");
         }
     }
 
@@ -145,7 +146,7 @@
                 throw new InvalidOperationException("Can't open the specified file: '" + file + "'", e);
             }
 
-            LOG.log(POILogger.ERROR, "Error in zip file ", file, " - falling back to stream processing (i.e. ignoring zip central directory)");
+            LOG.atError().log("Error in zip file {} - falling back to stream processing (i.e. ignoring zip central directory)", file);
             ze = openZipEntrySourceStream(file);
         }
         this.zipArchive = ze;
@@ -311,7 +312,7 @@
                     : PackagingURIHelper.createPartName(ZipHelper.getOPCNameFromZipItemName(entryName));
             } catch (Exception e) {
                 // We assume we can continue, even in degraded mode ...
-                LOG.log(POILogger.WARN,"Entry ", entryName, " is not valid, so this part won't be add to the package.", e);
+                LOG.atWarn().withThrowable(e).log("Entry {} is not valid, so this part won't be add to the package.", entryName);
             }
 
             this.partName = ppn;
@@ -370,7 +371,7 @@
         try {
             return new MemoryPackagePart(this, partName, contentType, loadRelationships);
         } catch (InvalidFormatException e) {
-            LOG.log(POILogger.WARN, e);
+            LOG.atWarn().withThrowable(e).log("Failed to create part {}", partName);
             return null;
         }
     }
@@ -437,9 +438,7 @@
 			} finally {
 				// Either the save operation succeed or not, we delete the temporary file
 				if (!tempFile.delete()) {
-					LOG.log(POILogger.WARN, "The temporary file: '",
-					    targetFile.getAbsolutePath(),
-					    "' cannot be deleted ! Make sure that no other application use it.");
+                    LOG.atWarn().log("The temporary file: '{}' cannot be deleted ! Make sure that no other application use it.", targetFile.getAbsolutePath());
 				}
 			}
 		}
@@ -496,7 +495,7 @@
 			// we save it as well
 			if (this.getPartsByRelationshipType(PackageRelationshipTypes.CORE_PROPERTIES).size() == 0 &&
                 this.getPartsByRelationshipType(PackageRelationshipTypes.CORE_PROPERTIES_ECMA376).size() == 0    ) {
-				LOG.log(POILogger.DEBUG,"Save core properties part");
+				LOG.atDebug().log("Save core properties part");
 
 				// Ensure that core properties are added if missing
 				getPackageProperties();
@@ -516,11 +515,11 @@
 			}
 
             // Save content type part.
-            LOG.log(POILogger.DEBUG,"Save content types part");
+            LOG.atDebug().log("Save content types part");
             this.contentTypeManager.save(zos);
 
 			// Save package relationships part.
-			LOG.log(POILogger.DEBUG,"Save package relationships");
+			LOG.atDebug().log("Save package relationships");
 			ZipPartMarshaller.marshallRelationshipPart(this.getRelationships(),
 					PackagingURIHelper.PACKAGE_RELATIONSHIPS_ROOT_PART_NAME,
 					zos);
@@ -534,13 +533,13 @@
                 }
 
 				final PackagePartName ppn = part.getPartName();
-				LOG.log(POILogger.DEBUG,"Save part '", ZipHelper.getZipItemNameFromOPCName(ppn.getName()), "'");
+                LOG.atDebug().log(() -> new SimpleMessage("Save part '" + ZipHelper.getZipItemNameFromOPCName(ppn.getName()) + "'"));
 				final PartMarshaller marshaller = partMarshallers.get(part._contentType);
 
 				final PartMarshaller pm = (marshaller != null) ? marshaller : defaultPartMarshaller;
                 if (!pm.marshall(part, zos)) {
                     String errMsg = "The part " + ppn.getURI() + " failed to be saved in the stream with marshaller " + pm +
-                            ". Enable logging via POILogger for more details.";
+                            ". Enable logging via Log4j 2 for more details.";
                     throw new OpenXML4JException(errMsg);
                 }
 			}
diff --git a/src/ooxml/java/org/apache/poi/openxml4j/opc/internal/ZipContentTypeManager.java b/src/ooxml/java/org/apache/poi/openxml4j/opc/internal/ZipContentTypeManager.java
index 3040262..597335e 100644
--- a/src/ooxml/java/org/apache/poi/openxml4j/opc/internal/ZipContentTypeManager.java
+++ b/src/ooxml/java/org/apache/poi/openxml4j/opc/internal/ZipContentTypeManager.java
@@ -23,11 +23,11 @@
 
 import org.apache.commons.compress.archivers.zip.ZipArchiveEntry;
 import org.apache.commons.compress.archivers.zip.ZipArchiveOutputStream;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
 import org.apache.poi.openxml4j.opc.OPCPackage;
 import org.apache.poi.openxml4j.opc.StreamHelper;
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
 import org.w3c.dom.Document;
 
 /**
@@ -38,7 +38,7 @@
  * @see ContentTypeManager
  */
 public class ZipContentTypeManager extends ContentTypeManager {
-    private static final POILogger LOG = POILogFactory.getLogger(ZipContentTypeManager.class);
+    private static final Logger LOG = LogManager.getLogger(ZipContentTypeManager.class);
 
 	/**
 	 * Delegate constructor to the super constructor.
@@ -71,8 +71,7 @@
 				zos.closeArchiveEntry();
 			}
 		} catch (IOException ioe) {
-			LOG.log(POILogger.ERROR, "Cannot write: ", CONTENT_TYPES_PART_NAME,
-					" in Zip !", ioe);
+			LOG.atError().withThrowable(ioe).log("Cannot write: " + CONTENT_TYPES_PART_NAME + " in Zip !");
 			return false;
 		}
 	}
diff --git a/src/ooxml/java/org/apache/poi/openxml4j/opc/internal/marshallers/DefaultMarshaller.java b/src/ooxml/java/org/apache/poi/openxml4j/opc/internal/marshallers/DefaultMarshaller.java
index 16a5917..970768c 100644
--- a/src/ooxml/java/org/apache/poi/openxml4j/opc/internal/marshallers/DefaultMarshaller.java
+++ b/src/ooxml/java/org/apache/poi/openxml4j/opc/internal/marshallers/DefaultMarshaller.java
@@ -38,7 +38,7 @@
 	 * @param part The {@link PackagePart} to store.
 	 * @param out Output stream to save this part.
 	 * @return true if the content has been successfully stored, false otherwise.
-	 *         More information about errors may be logged via {@link org.apache.poi.util.POILogger}
+	 *         More information about errors may be logged via Log4j 2.
 	 * @throws OpenXML4JException
 	 *             If any error occur.
 	 */
diff --git a/src/ooxml/java/org/apache/poi/openxml4j/opc/internal/marshallers/ZipPartMarshaller.java b/src/ooxml/java/org/apache/poi/openxml4j/opc/internal/marshallers/ZipPartMarshaller.java
index c1e058e..384ad76 100644
--- a/src/ooxml/java/org/apache/poi/openxml4j/opc/internal/marshallers/ZipPartMarshaller.java
+++ b/src/ooxml/java/org/apache/poi/openxml4j/opc/internal/marshallers/ZipPartMarshaller.java
@@ -24,6 +24,8 @@
 
 import org.apache.commons.compress.archivers.zip.ZipArchiveEntry;
 import org.apache.commons.compress.archivers.zip.ZipArchiveOutputStream;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.apache.poi.openxml4j.exceptions.OpenXML4JException;
 import org.apache.poi.openxml4j.opc.PackageNamespaces;
 import org.apache.poi.openxml4j.opc.PackagePart;
@@ -37,8 +39,6 @@
 import org.apache.poi.openxml4j.opc.internal.ZipHelper;
 import org.apache.poi.ooxml.util.DocumentHelper;
 import org.apache.poi.util.IOUtils;
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
 import org.apache.poi.xssf.usermodel.XSSFRelation;
 import org.w3c.dom.Document;
 import org.w3c.dom.Element;
@@ -47,7 +47,7 @@
  * Zip part marshaller. This marshaller is use to save any part in a zip stream.
  */
 public final class ZipPartMarshaller implements PartMarshaller {
-	private static final POILogger LOG = POILogFactory.getLogger(ZipPartMarshaller.class);
+	private static final Logger LOG = LogManager.getLogger(ZipPartMarshaller.class);
 
 	/**
 	 * Save the specified part to the given stream.
@@ -56,7 +56,7 @@
 	 * @param os The stream to write the data to
 	 * @return true if saving was successful or there was nothing to save,
 	 * 		false if an error occurred.
-	 * 		In case of errors, logging via the {@link POILogger} is used to provide more information.
+	 * 		In case of errors, logging via Log4j 2 is used to provide more information.
 	 * @throws OpenXML4JException
 	 *      Throws if the stream cannot be written to or an internal exception is thrown.
 	 */
@@ -64,7 +64,7 @@
 	public boolean marshall(PackagePart part, OutputStream os)
 			throws OpenXML4JException {
 		if (!(os instanceof ZipArchiveOutputStream)) {
-			LOG.log(POILogger.ERROR,"Unexpected class ", os.getClass().getName());
+			LOG.atError().log("Unexpected class {}", os.getClass().getName());
 			throw new OpenXML4JException("ZipOutputStream expected !");
 			// Normally should happen only in development phase, so just throw
 			// exception
@@ -91,8 +91,7 @@
 				zos.closeArchiveEntry();
 			}
 		} catch (IOException ioe) {
-			LOG.log(POILogger.ERROR,"Cannot write: ", part.getPartName(), ": in ZIP",
-					ioe);
+			LOG.atError().withThrowable(ioe).log("Cannot write: {}: in ZIP", part.getPartName());
 			return false;
 		}
 
@@ -120,7 +119,7 @@
 	 *            relationships serialization.
 	 * @return true if saving was successful,
 	 * 		false if an error occurred.
-	 * 		In case of errors, logging via the {@link POILogger} is used to provide more information.
+	 * 		In case of errors, logging via Log4j 2 is used to provide more information.
 	 */
 	public static boolean marshallRelationshipPart(
 			PackageRelationshipCollection rels, PackagePartName relPartName,
@@ -186,7 +185,7 @@
 				zos.closeArchiveEntry();
 			}
 		} catch (IOException e) {
-			LOG.log(POILogger.ERROR,"Cannot create zip entry ", relPartName, e);
+			LOG.atError().withThrowable(e).log("Cannot create zip entry {}", relPartName);
 			return false;
 		}
 	}
diff --git a/src/ooxml/java/org/apache/poi/poifs/crypt/dsig/KeyInfoKeySelector.java b/src/ooxml/java/org/apache/poi/poifs/crypt/dsig/KeyInfoKeySelector.java
index 04ac6fd..e7a4eba 100644
--- a/src/ooxml/java/org/apache/poi/poifs/crypt/dsig/KeyInfoKeySelector.java
+++ b/src/ooxml/java/org/apache/poi/poifs/crypt/dsig/KeyInfoKeySelector.java
@@ -38,8 +38,8 @@
 import javax.xml.crypto.dsig.keyinfo.KeyInfo;
 import javax.xml.crypto.dsig.keyinfo.X509Data;
 
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 
 /**
  * JSR105 key selector implementation using the ds:KeyInfo data of the signature
@@ -47,14 +47,14 @@
  */
 public class KeyInfoKeySelector extends KeySelector implements KeySelectorResult {
 
-    private static final POILogger LOG = POILogFactory.getLogger(KeyInfoKeySelector.class);
+    private static final Logger LOG = LogManager.getLogger(KeyInfoKeySelector.class);
 
     private final List<X509Certificate> certChain = new ArrayList<>();
 
     @SuppressWarnings("unchecked")
     @Override
     public KeySelectorResult select(KeyInfo keyInfo, Purpose purpose, AlgorithmMethod method, XMLCryptoContext context) throws KeySelectorException {
-        LOG.log(POILogger.DEBUG, "select key");
+        LOG.atDebug().log("select key");
         if (null == keyInfo) {
             throw new KeySelectorException("no ds:KeyInfo present");
         }
@@ -71,7 +71,7 @@
                     continue;
                 }
                 X509Certificate certificate = (X509Certificate) x509DataObject;
-                LOG.log(POILogger.DEBUG, "certificate", certificate.getSubjectX500Principal());
+                LOG.atDebug().log("certificate: {}", certificate.getSubjectX500Principal());
                 certChain.add(certificate);
             }
         }
diff --git a/src/ooxml/java/org/apache/poi/poifs/crypt/dsig/OOXMLURIDereferencer.java b/src/ooxml/java/org/apache/poi/poifs/crypt/dsig/OOXMLURIDereferencer.java
index b809b06..d38088c 100644
--- a/src/ooxml/java/org/apache/poi/poifs/crypt/dsig/OOXMLURIDereferencer.java
+++ b/src/ooxml/java/org/apache/poi/poifs/crypt/dsig/OOXMLURIDereferencer.java
@@ -38,19 +38,19 @@
 import javax.xml.crypto.URIReferenceException;
 import javax.xml.crypto.XMLCryptoContext;
 
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
 import org.apache.poi.openxml4j.opc.PackagePart;
 import org.apache.poi.openxml4j.opc.PackagePartName;
 import org.apache.poi.openxml4j.opc.PackagingURIHelper;
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
 
 /**
  * JSR105 URI dereferencer for Office Open XML documents.
  */
 public class OOXMLURIDereferencer implements URIDereferencer {
 
-    private static final POILogger LOG = POILogFactory.getLogger(OOXMLURIDereferencer.class);
+    private static final Logger LOG = LogManager.getLogger(OOXMLURIDereferencer.class);
 
     private SignatureInfo signatureInfo;
     private URIDereferencer baseUriDereferencer;
@@ -77,7 +77,7 @@
 
         PackagePart part = findPart(uri);
         if (part == null) {
-            LOG.log(POILogger.DEBUG, "cannot resolve, delegating to base DOM URI dereferencer", uri);
+            LOG.atDebug().log("cannot resolve {}, delegating to base DOM URI dereferencer", uri);
             return baseUriDereferencer.dereference(uriReference, context);
         }
 
@@ -105,11 +105,11 @@
     }
 
     private PackagePart findPart(URI uri) {
-        LOG.log(POILogger.DEBUG, "dereference", uri);
+        LOG.atDebug().log("dereference: {}", uri);
 
         String path = uri.getPath();
         if (path == null || path.isEmpty()) {
-            LOG.log(POILogger.DEBUG, "illegal part name (expected)", uri);
+            LOG.atDebug().log("illegal part name (expected): {}", uri);
             return null;
         }
 
@@ -118,7 +118,7 @@
             ppn = PackagingURIHelper.createPartName(path);
             return signatureInfo.getOpcPackage().getPart(ppn);
         } catch (InvalidFormatException e) {
-            LOG.log(POILogger.WARN, "illegal part name (not expected)", uri);
+            LOG.atWarn().log("illegal part name (not expected) in {}", uri);
             return null;
         }
     }
diff --git a/src/ooxml/java/org/apache/poi/poifs/crypt/dsig/SignatureConfig.java b/src/ooxml/java/org/apache/poi/poifs/crypt/dsig/SignatureConfig.java
index 07702f6..98cb193 100644
--- a/src/ooxml/java/org/apache/poi/poifs/crypt/dsig/SignatureConfig.java
+++ b/src/ooxml/java/org/apache/poi/poifs/crypt/dsig/SignatureConfig.java
@@ -44,6 +44,8 @@
 import javax.xml.crypto.dsig.XMLSignatureFactory;
 import javax.xml.crypto.dsig.keyinfo.KeyInfoFactory;
 
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.apache.poi.EncryptedDocumentException;
 import org.apache.poi.hpsf.ClassID;
 import org.apache.poi.openxml4j.opc.OPCPackage;
@@ -60,8 +62,6 @@
 import org.apache.poi.poifs.crypt.dsig.services.TimeStampServiceValidator;
 import org.apache.poi.util.Internal;
 import org.apache.poi.util.LocaleUtil;
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
 import org.apache.poi.util.Removal;
 import org.apache.xml.security.signature.XMLSignature;
 
@@ -76,7 +76,7 @@
 
     public static final String SIGNATURE_TIME_FORMAT = "yyyy-MM-dd'T'HH:mm:ss'Z'";
 
-    private static final POILogger LOG = POILogFactory.getLogger(SignatureConfig.class);
+    private static final Logger LOG = LogManager.getLogger(SignatureConfig.class);
     private static final String DigestMethod_SHA224 = "http://www.w3.org/2001/04/xmldsig-more#sha224";
     private static final String DigestMethod_SHA384 = "http://www.w3.org/2001/04/xmldsig-more#sha384";
     private static final String XMLSEC_SANTUARIO = "org.apache.jcp.xml.dsig.internal.dom.XMLDSigRI";
@@ -350,7 +350,7 @@
             try {
                 this.executionTime = fmt.parse(executionTime);
             } catch (ParseException e) {
-                LOG.log(POILogger.WARN, "Illegal execution time: ", executionTime);
+                LOG.atWarn().log("Illegal execution time: {}. Must be formatted as " + SIGNATURE_TIME_FORMAT, executionTime);
             }
         }
     }
diff --git a/src/ooxml/java/org/apache/poi/poifs/crypt/dsig/SignatureInfo.java b/src/ooxml/java/org/apache/poi/poifs/crypt/dsig/SignatureInfo.java
index b06a01f..8f43ef1 100644
--- a/src/ooxml/java/org/apache/poi/poifs/crypt/dsig/SignatureInfo.java
+++ b/src/ooxml/java/org/apache/poi/poifs/crypt/dsig/SignatureInfo.java
@@ -52,6 +52,7 @@
 import javax.xml.crypto.dsig.SignedInfo;
 import javax.xml.crypto.dsig.TransformException;
 import javax.xml.crypto.dsig.XMLObject;
+import javax.xml.crypto.dsig.XMLSignature;
 import javax.xml.crypto.dsig.XMLSignatureException;
 import javax.xml.crypto.dsig.XMLSignatureFactory;
 import javax.xml.crypto.dsig.dom.DOMSignContext;
@@ -61,6 +62,8 @@
 import org.apache.jcp.xml.dsig.internal.dom.DOMReference;
 import org.apache.jcp.xml.dsig.internal.dom.DOMSignedInfo;
 import org.apache.jcp.xml.dsig.internal.dom.DOMSubTreeData;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.apache.poi.EncryptedDocumentException;
 import org.apache.poi.ooxml.util.DocumentHelper;
 import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
@@ -76,8 +79,6 @@
 import org.apache.poi.poifs.crypt.HashAlgorithm;
 import org.apache.poi.poifs.crypt.dsig.facets.SignatureFacet;
 import org.apache.poi.poifs.crypt.dsig.services.RelationshipTransformService;
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
 import org.apache.xml.security.Init;
 import org.apache.xml.security.utils.XMLUtils;
 import org.apache.xmlbeans.XmlOptions;
@@ -154,12 +155,12 @@
  * <ul>
  * <li>BouncyCastle bcpkix and bcprov (tested against 1.67)</li>
  * <li>Apache Santuario "xmlsec" (tested against 2.2.0)</li>
- * <li>and slf4j-api (tested against 1.7.30)</li>
+ * <li>and log4j-api (tested against 2.14.0)</li>
  * </ul>
  */
 public class SignatureInfo {
 
-    private static final POILogger LOG = POILogFactory.getLogger(SignatureInfo.class);
+    private static final Logger LOG = LogManager.getLogger(SignatureInfo.class);
 
     private SignatureConfig signatureConfig;
     private OPCPackage opcPackage;
@@ -313,11 +314,11 @@
                     return false;
                 }
                 sigPart = opcPackage.getPart(sigOrigRels.next());
-                LOG.log(POILogger.DEBUG, "Digital Signature Origin part", sigPart);
+                LOG.atDebug().log("Digital Signature Origin part: {}", sigPart);
                 try {
                     sigRels = sigPart.getRelationshipsByType(PackageRelationshipTypes.DIGITAL_SIGNATURE).iterator();
                 } catch (InvalidFormatException e) {
-                    LOG.log(POILogger.WARN, "Reference to signature is invalid.", e);
+                    LOG.atWarn().withThrowable(e).log("Reference to signature is invalid.");
                 }
             }
             return true;
@@ -332,9 +333,9 @@
                         throw new NoSuchElementException();
                     }
                     sigRelPart = sigPart.getRelatedPart(sigRels.next());
-                    LOG.log(POILogger.DEBUG, "XML Signature part", sigRelPart);
+                    LOG.atDebug().log("XML Signature part: {}", sigRelPart);
                 } catch (InvalidFormatException e) {
-                    LOG.log(POILogger.WARN, "Reference to signature is invalid.", e);
+                    LOG.atWarn().withThrowable(e).log("Reference to signature is invalid.");
                 }
             } while (sigRelPart == null);
             return new SignaturePart(sigRelPart, SignatureInfo.this);
@@ -378,7 +379,7 @@
          */
         List<XMLObject> objects = new ArrayList<>();
         for (SignatureFacet signatureFacet : signatureConfig.getSignatureFacets()) {
-            LOG.log(POILogger.DEBUG, "invoking signature facet: ", signatureFacet.getClass().getSimpleName());
+            LOG.atDebug().log("invoking signature facet: {}", signatureFacet.getClass().getSimpleName());
             signatureFacet.preSign(this, document, references, objects);
         }
 
@@ -402,7 +403,7 @@
          * JSR105 ds:Signature creation
          */
         String signatureValueId = signatureConfig.getPackageSignatureId() + "-signature-value";
-        javax.xml.crypto.dsig.XMLSignature xmlSignature = signatureFactory
+        XMLSignature xmlSignature = signatureFactory
             .newXMLSignature(signedInfo, null, objects, signatureConfig.getPackageSignatureId(),
             signatureValueId);
 
@@ -415,10 +416,10 @@
          * Completion of undigested ds:References in the ds:Manifests.
          */
         for (XMLObject object : objects) {
-            LOG.log(POILogger.DEBUG, "object java type: ", object.getClass().getName());
+            LOG.atDebug().log("object java type: {}", object.getClass().getName());
             List<XMLStructure> objectContentList = object.getContent();
             for (XMLStructure objectContent : objectContentList) {
-                LOG.log(POILogger.DEBUG, "object content java type: ", objectContent.getClass().getName());
+                LOG.atDebug().log("object content java type: {}", objectContent.getClass().getName());
                 if (!(objectContent instanceof Manifest)) {
                     continue;
                 }
@@ -483,7 +484,7 @@
      */
     public void postSign(final DOMSignContext xmlSignContext, final String signatureValue)
     throws MarshalException {
-        LOG.log(POILogger.DEBUG, "postSign");
+        LOG.atDebug().log("postSign");
 
         final Document document = (Document)xmlSignContext.getParent();
 
@@ -527,7 +528,7 @@
         xo.setSaveSuggestedPrefixes(namespaceMap);
         xo.setUseDefaultNamespace();
 
-        LOG.log(POILogger.DEBUG, "output signed Office OpenXML document");
+        LOG.atDebug().log("output signed Office OpenXML document");
 
         /*
          * Copy the original OOXML content to the signed OOXML package. During
@@ -593,8 +594,7 @@
             return (Element)sigValNl.item(0);
         }
 
-        LOG.log(POILogger.WARN, "Signature element '", localName, "' was ",
-                (sigValNl.getLength() == 0 ? "not found" : "multiple times"));
+        LOG.atWarn().log("Signature element '{}' was {}", localName, sigValNl.getLength() == 0 ? "not found" : "multiple times");
 
         return null;
     }
@@ -704,7 +704,7 @@
             try {
                 return (Provider)Class.forName(className).getDeclaredConstructor().newInstance();
             } catch (Exception e) {
-                LOG.log(POILogger.DEBUG, "XMLDsig-Provider '", className, "' can't be found - trying next.");
+                LOG.atDebug().log("XMLDsig-Provider '{}' can't be found - trying next.", className);
                 return null;
             }
         }
diff --git a/src/ooxml/java/org/apache/poi/poifs/crypt/dsig/SignaturePart.java b/src/ooxml/java/org/apache/poi/poifs/crypt/dsig/SignaturePart.java
index d120d65..1fd4151 100644
--- a/src/ooxml/java/org/apache/poi/poifs/crypt/dsig/SignaturePart.java
+++ b/src/ooxml/java/org/apache/poi/poifs/crypt/dsig/SignaturePart.java
@@ -40,12 +40,12 @@
 import javax.xml.xpath.XPathConstants;
 import javax.xml.xpath.XPathExpressionException;
 
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.apache.poi.EncryptedDocumentException;
 import org.apache.poi.ooxml.util.DocumentHelper;
 import org.apache.poi.ooxml.util.XPathHelper;
 import org.apache.poi.openxml4j.opc.PackagePart;
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
 import org.apache.xmlbeans.XmlException;
 import org.w3.x2000.x09.xmldsig.SignatureDocument;
 import org.w3c.dom.Document;
@@ -54,7 +54,7 @@
 import org.xml.sax.SAXException;
 
 public class SignaturePart {
-    private static final POILogger LOG = POILogFactory.getLogger(SignaturePart.class);
+    private static final Logger LOG = LogManager.getLogger(SignaturePart.class);
     private static final String XMLSEC_VALIDATE_MANIFEST = "org.jcp.xml.dsig.validateManifests";
 
 
@@ -139,23 +139,23 @@
             return valid;
         } catch (IOException e) {
             String s = "error in reading document";
-            LOG.log(POILogger.ERROR, s, e);
+            LOG.atError().withThrowable(e).log(s);
             throw new EncryptedDocumentException(s, e);
         } catch (SAXException e) {
             String s = "error in parsing document";
-            LOG.log(POILogger.ERROR, s, e);
+            LOG.atError().withThrowable(e).log(s);
             throw new EncryptedDocumentException(s, e);
         } catch (XPathExpressionException e) {
             String s = "error in searching document with xpath expression";
-            LOG.log(POILogger.ERROR, s, e);
+            LOG.atError().withThrowable(e).log(s);
             throw new EncryptedDocumentException(s, e);
         } catch (MarshalException e) {
             String s = "error in unmarshalling the signature";
-            LOG.log(POILogger.ERROR, s, e);
+            LOG.atError().withThrowable(e).log(s);
             throw new EncryptedDocumentException(s, e);
         } catch (XMLSignatureException e) {
             String s = "error in validating the signature";
-            LOG.log(POILogger.ERROR, s, e);
+            LOG.atError().withThrowable(e).log(s);
             throw new EncryptedDocumentException(s, e);
         }
     }
diff --git a/src/ooxml/java/org/apache/poi/poifs/crypt/dsig/facets/KeyInfoSignatureFacet.java b/src/ooxml/java/org/apache/poi/poifs/crypt/dsig/facets/KeyInfoSignatureFacet.java
index 0943a8a..d59f4c9 100644
--- a/src/ooxml/java/org/apache/poi/poifs/crypt/dsig/facets/KeyInfoSignatureFacet.java
+++ b/src/ooxml/java/org/apache/poi/poifs/crypt/dsig/facets/KeyInfoSignatureFacet.java
@@ -40,10 +40,10 @@
 import javax.xml.crypto.dsig.keyinfo.X509Data;
 
 import org.apache.jcp.xml.dsig.internal.dom.DOMKeyInfo;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.apache.poi.poifs.crypt.dsig.SignatureConfig;
 import org.apache.poi.poifs.crypt.dsig.SignatureInfo;
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
 import org.w3c.dom.Document;
 import org.w3c.dom.Element;
 import org.w3c.dom.Node;
@@ -56,12 +56,12 @@
  */
 public class KeyInfoSignatureFacet implements SignatureFacet {
 
-    private static final POILogger LOG = POILogFactory.getLogger(KeyInfoSignatureFacet.class);
+    private static final Logger LOG = LogManager.getLogger(KeyInfoSignatureFacet.class);
 
     @Override
     public void postSign(SignatureInfo signatureInfo, Document document)
     throws MarshalException {
-        LOG.log(POILogger.DEBUG, "postSign");
+        LOG.atDebug().log("postSign");
 
         NodeList nl = document.getElementsByTagNameNS(XML_DIGSIG_NS, "Object");
 
diff --git a/src/ooxml/java/org/apache/poi/poifs/crypt/dsig/facets/OOXMLSignatureFacet.java b/src/ooxml/java/org/apache/poi/poifs/crypt/dsig/facets/OOXMLSignatureFacet.java
index fb88e96..6f5061a 100644
--- a/src/ooxml/java/org/apache/poi/poifs/crypt/dsig/facets/OOXMLSignatureFacet.java
+++ b/src/ooxml/java/org/apache/poi/poifs/crypt/dsig/facets/OOXMLSignatureFacet.java
@@ -54,6 +54,8 @@
 
 import com.microsoft.schemas.office.x2006.digsig.CTSignatureInfoV1;
 import com.microsoft.schemas.office.x2006.digsig.SignatureInfoV1Document;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
 import org.apache.poi.openxml4j.opc.ContentTypes;
 import org.apache.poi.openxml4j.opc.OPCPackage;
@@ -68,8 +70,6 @@
 import org.apache.poi.poifs.crypt.dsig.SignatureInfo;
 import org.apache.poi.poifs.crypt.dsig.services.RelationshipTransformService;
 import org.apache.poi.poifs.crypt.dsig.services.RelationshipTransformService.RelationshipTransformParameterSpec;
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
 import org.openxmlformats.schemas.xpackage.x2006.digitalSignature.CTSignatureTime;
 import org.openxmlformats.schemas.xpackage.x2006.digitalSignature.SignatureTimeDocument;
 import org.w3c.dom.Document;
@@ -82,7 +82,7 @@
  */
 public class OOXMLSignatureFacet implements SignatureFacet {
 
-    private static final POILogger LOG = POILogFactory.getLogger(OOXMLSignatureFacet.class);
+    private static final Logger LOG = LogManager.getLogger(OOXMLSignatureFacet.class);
     private static final String ID_PACKAGE_OBJECT = "idPackageObject";
 
     @Override
@@ -92,7 +92,7 @@
         , List<Reference> references
         , List<XMLObject> objects)
     throws XMLSignatureException {
-        LOG.log(POILogger.DEBUG, "pre sign");
+        LOG.atDebug().log("pre sign");
         addManifestObject(signatureInfo, document, references, objects);
         addSignatureInfo(signatureInfo, document, references, objects);
     }
@@ -178,7 +178,7 @@
 
                 if (relationshipType.endsWith("customXml")
                     && !(contentType.equals("inkml+xml") || contentType.equals("text/xml"))) {
-                    LOG.log(POILogger.DEBUG, "skipping customXml with content type: ", contentType);
+                    LOG.atDebug().log("skipping customXml with content type: {}", contentType);
                     continue;
                 }
 
@@ -212,7 +212,7 @@
         }
         try {
             pn = new URI(pn).normalize().getPath().replace('\\', '/');
-            LOG.log(POILogger.DEBUG, "part name: ", pn);
+            LOG.atDebug().log("part name: {}", pn);
         } catch (URISyntaxException e) {
             throw new XMLSignatureException(e);
         }
@@ -230,7 +230,7 @@
         CTSignatureTime ctTime = sigTime.addNewSignatureTime();
         ctTime.setFormat("YYYY-MM-DDThh:mm:ssTZD");
         ctTime.setValue(signatureConfig.formatExecutionTime());
-        LOG.log(POILogger.DEBUG, "execution time: ", ctTime.getValue());
+        LOG.atDebug().log("execution time: {}", ctTime.getValue());
 
         Element n = (Element)document.importNode(ctTime.getDomNode(),true);
         List<XMLStructure> signatureTimeContent = new ArrayList<>();
@@ -328,7 +328,7 @@
     }
 
     protected static boolean isSignedRelationship(String relationshipType) {
-        LOG.log(POILogger.DEBUG, "relationship type: ", relationshipType);
+        LOG.atDebug().log("relationship type: {}", relationshipType);
         String rt = relationshipType.replaceFirst(".*/relationships/", "");
         return (signed.contains(rt) || rt.endsWith("customXml"));
     }
diff --git a/src/ooxml/java/org/apache/poi/poifs/crypt/dsig/facets/XAdESSignatureFacet.java b/src/ooxml/java/org/apache/poi/poifs/crypt/dsig/facets/XAdESSignatureFacet.java
index 8ad617f..d18af54 100644
--- a/src/ooxml/java/org/apache/poi/poifs/crypt/dsig/facets/XAdESSignatureFacet.java
+++ b/src/ooxml/java/org/apache/poi/poifs/crypt/dsig/facets/XAdESSignatureFacet.java
@@ -32,7 +32,6 @@
 import java.security.cert.CertificateEncodingException;
 import java.security.cert.X509Certificate;
 import java.util.Calendar;
-import java.util.Collections;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Locale;
@@ -47,13 +46,13 @@
 import javax.xml.crypto.dsig.XMLObject;
 import javax.xml.crypto.dsig.XMLSignatureException;
 
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.apache.poi.poifs.crypt.CryptoFunctions;
 import org.apache.poi.poifs.crypt.HashAlgorithm;
 import org.apache.poi.poifs.crypt.dsig.SignatureConfig;
 import org.apache.poi.poifs.crypt.dsig.SignatureInfo;
 import org.apache.poi.poifs.crypt.dsig.services.SignaturePolicyService;
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
 import org.apache.xmlbeans.XmlCursor;
 import org.apache.xmlbeans.XmlObject;
 import org.apache.xmlbeans.XmlString;
@@ -92,7 +91,7 @@
  */
 public class XAdESSignatureFacet implements SignatureFacet {
 
-    private static final POILogger LOG = POILogFactory.getLogger(XAdESSignatureFacet.class);
+    private static final Logger LOG = LogManager.getLogger(XAdESSignatureFacet.class);
 
     private static final String XADES_TYPE = "http://uri.etsi.org/01903#SignedProperties";
 
@@ -106,7 +105,7 @@
         , List<Reference> references
         , List<XMLObject> objects)
     throws XMLSignatureException {
-        LOG.log(POILogger.DEBUG, "preSign");
+        LOG.atDebug().log("preSign");
 
         SignatureConfig signatureConfig = signatureInfo.getSignatureConfig();
 
@@ -241,7 +240,7 @@
         assert(nl.getLength() == 1);
         ((Element)nl.item(0)).setIdAttribute("Id", true);
 
-        List<XMLStructure> xadesObjectContent = Collections.singletonList(new DOMStructure(qualDocEl));
+        List<XMLStructure> xadesObjectContent = singletonList(new DOMStructure(qualDocEl));
         XMLObject xo = signatureInfo.getSignatureFactory().newXMLObject(xadesObjectContent, null, null, null);
         return xo;
     }
diff --git a/src/ooxml/java/org/apache/poi/poifs/crypt/dsig/facets/XAdESXLSignatureFacet.java b/src/ooxml/java/org/apache/poi/poifs/crypt/dsig/facets/XAdESXLSignatureFacet.java
index 3c70649..18f28f4 100644
--- a/src/ooxml/java/org/apache/poi/poifs/crypt/dsig/facets/XAdESXLSignatureFacet.java
+++ b/src/ooxml/java/org/apache/poi/poifs/crypt/dsig/facets/XAdESXLSignatureFacet.java
@@ -47,11 +47,11 @@
 
 import javax.xml.crypto.MarshalException;
 
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.apache.poi.poifs.crypt.dsig.SignatureConfig;
 import org.apache.poi.poifs.crypt.dsig.SignatureInfo;
 import org.apache.poi.poifs.crypt.dsig.services.RevocationData;
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
 import org.apache.xml.security.c14n.Canonicalizer;
 import org.apache.xmlbeans.XmlException;
 import org.bouncycastle.asn1.ASN1InputStream;
@@ -87,7 +87,7 @@
  */
 public class XAdESXLSignatureFacet implements SignatureFacet {
 
-    private static final POILogger LOG = POILogFactory.getLogger(XAdESXLSignatureFacet.class);
+    private static final Logger LOG = LogManager.getLogger(XAdESXLSignatureFacet.class);
 
     private final CertificateFactory certificateFactory;
 
@@ -101,7 +101,7 @@
 
     @Override
     public void postSign(SignatureInfo signatureInfo, Document document) throws MarshalException {
-        LOG.log(POILogger.DEBUG, "XAdES-X-L post sign phase");
+        LOG.atDebug().log("XAdES-X-L post sign phase");
 
         SignatureConfig signatureConfig = signatureInfo.getSignatureConfig();
 
@@ -139,7 +139,7 @@
         }
 
         RevocationData tsaRevocationDataXadesT = new RevocationData();
-        LOG.log(POILogger.DEBUG, "creating XAdES-T time-stamp");
+        LOG.atDebug().log("creating XAdES-T time-stamp");
         XAdESTimeStampType signatureTimeStamp = createXAdESTimeStamp
             (signatureInfo, Collections.singletonList(nlSigVal.item(0)), tsaRevocationDataXadesT);
 
@@ -259,7 +259,7 @@
         timeStampNodesXadesX1.add(completeRevocationRefs.getDomNode());
 
         RevocationData tsaRevocationDataXadesX1 = new RevocationData();
-        LOG.log(POILogger.DEBUG, "creating XAdES-X time-stamp");
+        LOG.atDebug().log("creating XAdES-X time-stamp");
         XAdESTimeStampType timeStampXadesX1 = createXAdESTimeStamp
             (signatureInfo, timeStampNodesXadesX1, tsaRevocationDataXadesX1);
         if (tsaRevocationDataXadesX1.hasRevocationDataEntries()) {
diff --git a/src/ooxml/java/org/apache/poi/poifs/crypt/dsig/services/RelationshipTransformService.java b/src/ooxml/java/org/apache/poi/poifs/crypt/dsig/services/RelationshipTransformService.java
index a2069c8..d8fc9d4 100644
--- a/src/ooxml/java/org/apache/poi/poifs/crypt/dsig/services/RelationshipTransformService.java
+++ b/src/ooxml/java/org/apache/poi/poifs/crypt/dsig/services/RelationshipTransformService.java
@@ -24,6 +24,7 @@
 
 package org.apache.poi.poifs.crypt.dsig.services;
 
+import static org.apache.logging.log4j.util.Unbox.box;
 import static org.apache.poi.ooxml.POIXMLTypeLoader.DEFAULT_XML_OPTIONS;
 import static org.apache.poi.poifs.crypt.dsig.facets.SignatureFacet.OO_DIGSIG_NS;
 import static org.apache.poi.poifs.crypt.dsig.facets.SignatureFacet.XML_NS;
@@ -49,9 +50,9 @@
 import javax.xml.crypto.dsig.spec.TransformParameterSpec;
 
 import org.apache.jcp.xml.dsig.internal.dom.ApacheNodeSetData;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.apache.poi.ooxml.util.DocumentHelper;
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
 import org.apache.poi.util.SuppressForbidden;
 import org.apache.xml.security.signature.XMLSignatureInput;
 import org.apache.xmlbeans.XmlException;
@@ -77,7 +78,7 @@
 
     private final List<String> sourceIds;
 
-    private static final POILogger LOG = POILogFactory.getLogger(RelationshipTransformService.class);
+    private static final Logger LOG = LogManager.getLogger(RelationshipTransformService.class);
 
     /**
      * Relationship Transform parameter specification class.
@@ -107,14 +108,14 @@
 
     public RelationshipTransformService() {
         super();
-        LOG.log(POILogger.DEBUG, "constructor");
+        LOG.atDebug().log("constructor");
         this.sourceIds = new ArrayList<>();
     }
 
     /**
      * Register the provider for this TransformService
      *
-     * @see javax.xml.crypto.dsig.TransformService
+     * @see TransformService
      */
     public static synchronized void registerDsigProvider() {
         // the xml signature classes will try to find a special TransformerService,
@@ -127,7 +128,7 @@
 
     @Override
     public void init(TransformParameterSpec params) throws InvalidAlgorithmParameterException {
-        LOG.log(POILogger.DEBUG, "init(params)");
+        LOG.atDebug().log("init(params)");
         if (!(params instanceof RelationshipTransformParameterSpec)) {
             throw new InvalidAlgorithmParameterException();
         }
@@ -137,8 +138,8 @@
 
     @Override
     public void init(XMLStructure parent, XMLCryptoContext context) throws InvalidAlgorithmParameterException {
-        LOG.log(POILogger.DEBUG, "init(parent,context)");
-        LOG.log(POILogger.DEBUG, "parent java type: ", parent.getClass().getName());
+        LOG.atDebug().log("init(parent,context)");
+        LOG.atDebug().log("parent java type: {}", parent.getClass().getName());
         DOMStructure domParent = (DOMStructure) parent;
         Node parentNode = domParent.getNode();
 
@@ -146,11 +147,11 @@
             TransformDocument transDoc = TransformDocument.Factory.parse(parentNode, DEFAULT_XML_OPTIONS);
             XmlObject[] xoList = transDoc.getTransform().selectChildren(RelationshipReferenceDocument.type.getDocumentElementName());
             if (xoList.length == 0) {
-                LOG.log(POILogger.WARN, "no RelationshipReference/@SourceId parameters present");
+                LOG.atWarn().log("no RelationshipReference/@SourceId parameters present");
             }
             for (XmlObject xo : xoList) {
                 String sourceId = ((CTRelationshipReference)xo).getSourceId();
-                LOG.log(POILogger.DEBUG, "sourceId: ", sourceId);
+                LOG.atDebug().log("sourceId: {}", sourceId);
                 this.sourceIds.add(sourceId);
             }
         } catch (XmlException e) {
@@ -160,7 +161,7 @@
 
     @Override
     public void marshalParams(XMLStructure parent, XMLCryptoContext context) throws MarshalException {
-        LOG.log(POILogger.DEBUG, "marshallParams(parent,context)");
+        LOG.atDebug().log("marshallParams(parent,context)");
         DOMStructure domParent = (DOMStructure) parent;
         Element parentNode = (Element)domParent.getNode();
         Document doc = parentNode.getOwnerDocument();
@@ -174,7 +175,7 @@
     }
 
     public AlgorithmParameterSpec getParameterSpec() {
-        LOG.log(POILogger.DEBUG, "getParameterSpec");
+        LOG.atDebug().log("getParameterSpec");
         return null;
     }
 
@@ -186,10 +187,10 @@
      * @see <a href="https://stackoverflow.com/questions/36063375">XML Relationship Transform Algorithm</a>
      */
     public Data transform(Data data, XMLCryptoContext context) throws TransformException {
-        LOG.log(POILogger.DEBUG, "transform(data,context)");
-        LOG.log(POILogger.DEBUG, "data java type: ", data.getClass().getName());
+        LOG.atDebug().log("transform(data,context)");
+        LOG.atDebug().log("data java type: {}", data.getClass().getName());
         OctetStreamData octetStreamData = (OctetStreamData) data;
-        LOG.log(POILogger.DEBUG, "URI: ", octetStreamData.getURI());
+        LOG.atDebug().log("URI: {}", octetStreamData.getURI());
         InputStream octetStream = octetStreamData.getOctetStream();
 
         Document doc;
@@ -223,18 +224,18 @@
             root.appendChild(el);
         }
 
-        LOG.log(POILogger.DEBUG, "# Relationship elements: ", rsList.size());
+        LOG.atDebug().log("# Relationship elements: {}", box(rsList.size()));
 
         return new ApacheNodeSetData(new XMLSignatureInput(root));
     }
 
     public Data transform(Data data, XMLCryptoContext context, OutputStream os) throws TransformException {
-        LOG.log(POILogger.DEBUG, "transform(data,context,os)");
+        LOG.atDebug().log("transform(data,context,os)");
         return null;
     }
 
     public boolean isFeatureSupported(String feature) {
-        LOG.log(POILogger.DEBUG, "isFeatureSupported(feature)");
+        LOG.atDebug().log("isFeatureSupported(feature)");
         return false;
     }
 }
diff --git a/src/ooxml/java/org/apache/poi/poifs/crypt/dsig/services/TSPTimeStampService.java b/src/ooxml/java/org/apache/poi/poifs/crypt/dsig/services/TSPTimeStampService.java
index fce674f..945cf9f 100644
--- a/src/ooxml/java/org/apache/poi/poifs/crypt/dsig/services/TSPTimeStampService.java
+++ b/src/ooxml/java/org/apache/poi/poifs/crypt/dsig/services/TSPTimeStampService.java
@@ -44,14 +44,15 @@
 import java.util.List;
 import java.util.Map;
 
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+import org.apache.logging.log4j.message.SimpleMessage;
 import org.apache.poi.poifs.crypt.CryptoFunctions;
 import org.apache.poi.poifs.crypt.HashAlgorithm;
 import org.apache.poi.poifs.crypt.dsig.SignatureConfig;
 import org.apache.poi.poifs.crypt.dsig.SignatureInfo;
 import org.apache.poi.util.HexDump;
 import org.apache.poi.util.IOUtils;
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
 import org.bouncycastle.asn1.ASN1ObjectIdentifier;
 import org.bouncycastle.asn1.cmp.PKIFailureInfo;
 import org.bouncycastle.asn1.nist.NISTObjectIdentifiers;
@@ -71,6 +72,8 @@
 import org.bouncycastle.tsp.TimeStampResponse;
 import org.bouncycastle.tsp.TimeStampToken;
 
+import static org.apache.logging.log4j.util.Unbox.box;
+
 /**
  * A TSP time-stamp service implementation.
  *
@@ -79,7 +82,7 @@
  */
 public class TSPTimeStampService implements TimeStampService {
 
-    private static final POILogger LOG = POILogFactory.getLogger(TSPTimeStampService.class);
+    private static final Logger LOG = LogManager.getLogger(TSPTimeStampService.class);
 
     /**
      * Maps the digest algorithm to corresponding OID value.
@@ -151,10 +154,10 @@
 
             int statusCode = huc.getResponseCode();
             if (statusCode != 200) {
-                LOG.log(POILogger.ERROR, "Error contacting TSP server ", signatureConfig.getTspUrl(),
-                        ", had status code ", statusCode, "/", huc.getResponseMessage());
-                throw new IOException("Error contacting TSP server " + signatureConfig.getTspUrl() +
-                        ", had status code " + statusCode + "/" + huc.getResponseMessage());
+                final String message = "Error contacting TSP server " + signatureConfig.getTspUrl() +
+                        ", had status code " + statusCode + "/" + huc.getResponseMessage();
+                LOG.atError().log(message);
+                throw new IOException(message);
             }
 
             // HTTP input validation
@@ -165,7 +168,7 @@
 
             bos = new ByteArrayOutputStream();
             IOUtils.copy(huc.getInputStream(), bos);
-            LOG.log(POILogger.DEBUG, "response content: ", HexDump.dump(bos.toByteArray(), 0, 0));
+            LOG.atDebug().log(() -> new SimpleMessage("response content: " + HexDump.dump(bos.toByteArray(), 0, 0)));
         } finally {
             huc.disconnect();
         }
@@ -188,13 +191,13 @@
         timeStampResponse.validate(request);
 
         if (0 != timeStampResponse.getStatus()) {
-            LOG.log(POILogger.DEBUG, "status: ", timeStampResponse.getStatus());
-            LOG.log(POILogger.DEBUG, "status string: ", timeStampResponse.getStatusString());
+            LOG.atDebug().log("status: {}", box(timeStampResponse.getStatus()));
+            LOG.atDebug().log("status string: {}", timeStampResponse.getStatusString());
             PKIFailureInfo failInfo = timeStampResponse.getFailInfo();
             if (null != failInfo) {
-                LOG.log(POILogger.DEBUG, "fail info int value: ", failInfo.intValue());
+                LOG.atDebug().log("fail info int value: {}", box(failInfo.intValue()));
                 if (/*PKIFailureInfo.unacceptedPolicy*/(1 << 8) == failInfo.intValue()) {
-                    LOG.log(POILogger.DEBUG, "unaccepted policy");
+                    LOG.atDebug().log("unaccepted policy");
                 }
             }
             throw new RuntimeException("timestamp response status != 0: "
@@ -204,8 +207,8 @@
         SignerId signerId = timeStampToken.getSID();
         BigInteger signerCertSerialNumber = signerId.getSerialNumber();
         X500Name signerCertIssuer = signerId.getIssuer();
-        LOG.log(POILogger.DEBUG, "signer cert serial number: ", signerCertSerialNumber);
-        LOG.log(POILogger.DEBUG, "signer cert issuer: ", signerCertIssuer);
+        LOG.atDebug().log("signer cert serial number: {}", signerCertSerialNumber);
+        LOG.atDebug().log("signer cert issuer: {}", signerCertIssuer);
 
         // TSP signer certificates retrieval
         Collection<X509CertificateHolder> certificates = timeStampToken.getCertificates().getMatches(null);
@@ -229,7 +232,7 @@
         x509converter.setProvider("BC");
         X509CertificateHolder certificate = signerCert;
         do {
-            LOG.log(POILogger.DEBUG, "adding to certificate chain: ", certificate.getSubject());
+            LOG.atDebug().log("adding to certificate chain: {}", certificate.getSubject());
             tspCertificateChain.add(x509converter.getCertificate(certificate));
             if (certificate.getSubject().equals(certificate.getIssuer())) {
                 break;
@@ -253,8 +256,7 @@
             signatureConfig.getTspValidator().validate(tspCertificateChain, revocationData);
         }
 
-        LOG.log(POILogger.DEBUG, "time-stamp token time: ",
-                timeStampToken.getTimeStampInfo().getGenTime());
+        LOG.atDebug().log("time-stamp token time: {}", timeStampToken.getTimeStampInfo().getGenTime());
 
         return timeStampToken.getEncoded();
     }
diff --git a/src/ooxml/java/org/apache/poi/poifs/crypt/temp/AesZipFileZipEntrySource.java b/src/ooxml/java/org/apache/poi/poifs/crypt/temp/AesZipFileZipEntrySource.java
index 454d17f..2fb1749 100644
--- a/src/ooxml/java/org/apache/poi/poifs/crypt/temp/AesZipFileZipEntrySource.java
+++ b/src/ooxml/java/org/apache/poi/poifs/crypt/temp/AesZipFileZipEntrySource.java
@@ -36,14 +36,14 @@
 import org.apache.commons.compress.archivers.zip.ZipArchiveInputStream;
 import org.apache.commons.compress.archivers.zip.ZipArchiveOutputStream;
 import org.apache.commons.compress.archivers.zip.ZipFile;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.apache.poi.openxml4j.util.ZipEntrySource;
 import org.apache.poi.poifs.crypt.ChainingMode;
 import org.apache.poi.poifs.crypt.CipherAlgorithm;
 import org.apache.poi.poifs.crypt.CryptoFunctions;
 import org.apache.poi.util.Beta;
 import org.apache.poi.util.IOUtils;
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
 import org.apache.poi.util.TempFile;
 
 /**
@@ -52,7 +52,7 @@
  */
 @Beta
 public final class AesZipFileZipEntrySource implements ZipEntrySource {
-    private static final POILogger LOG = POILogFactory.getLogger(AesZipFileZipEntrySource.class);
+    private static final Logger LOG = LogManager.getLogger(AesZipFileZipEntrySource.class);
 
     private static final String PADDING = "PKCS5Padding";
 
@@ -93,7 +93,7 @@
         if(!closed) {
             zipFile.close();
             if (!tmpFile.delete()) {
-                LOG.log(POILogger.WARN, tmpFile.getAbsolutePath()+" can't be removed (or was already removed.");
+                LOG.atWarn().log("{} can't be removed (or was already removed.", tmpFile.getAbsolutePath());
             }
         }
         closed = true;
diff --git a/src/ooxml/java/org/apache/poi/poifs/crypt/temp/EncryptedTempData.java b/src/ooxml/java/org/apache/poi/poifs/crypt/temp/EncryptedTempData.java
index a2d900b..e1ea120 100644
--- a/src/ooxml/java/org/apache/poi/poifs/crypt/temp/EncryptedTempData.java
+++ b/src/ooxml/java/org/apache/poi/poifs/crypt/temp/EncryptedTempData.java
@@ -32,12 +32,12 @@
 import javax.crypto.CipherOutputStream;
 import javax.crypto.spec.SecretKeySpec;
 
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.apache.poi.poifs.crypt.ChainingMode;
 import org.apache.poi.poifs.crypt.CipherAlgorithm;
 import org.apache.poi.poifs.crypt.CryptoFunctions;
 import org.apache.poi.util.Beta;
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
 import org.apache.poi.util.TempFile;
 
 /**
@@ -45,8 +45,8 @@
  */
 @Beta
 public class EncryptedTempData {
-    private static POILogger LOG = POILogFactory.getLogger(EncryptedTempData.class);
- 
+    private static Logger LOG = LogManager.getLogger(EncryptedTempData.class);
+
     private static final CipherAlgorithm cipherAlgorithm = CipherAlgorithm.aes128;
     private static final String PADDING = "PKCS5Padding";
     private final SecretKeySpec skeySpec;
@@ -91,7 +91,7 @@
      */
     public void dispose() {
         if (!tempFile.delete()) {
-            LOG.log(POILogger.WARN, tempFile.getAbsolutePath()+" can't be removed (or was already removed.");
+            LOG.atWarn().log("{} can't be removed (or was already removed).", tempFile.getAbsolutePath());
         }
     }
 }
diff --git a/src/ooxml/java/org/apache/poi/poifs/crypt/temp/SXSSFWorkbookWithCustomZipEntrySource.java b/src/ooxml/java/org/apache/poi/poifs/crypt/temp/SXSSFWorkbookWithCustomZipEntrySource.java
index 01a0b21..4ca8b86 100644
--- a/src/ooxml/java/org/apache/poi/poifs/crypt/temp/SXSSFWorkbookWithCustomZipEntrySource.java
+++ b/src/ooxml/java/org/apache/poi/poifs/crypt/temp/SXSSFWorkbookWithCustomZipEntrySource.java
@@ -22,17 +22,19 @@
 import java.io.IOException;
 import java.io.OutputStream;
 
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.apache.poi.openxml4j.util.ZipEntrySource;
 import org.apache.poi.util.Beta;
 import org.apache.poi.util.IOUtils;
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
 import org.apache.poi.xssf.streaming.SXSSFWorkbook;
 import org.apache.poi.xssf.streaming.SheetDataWriter;
 
+import static org.apache.logging.log4j.util.Unbox.box;
+
 @Beta
 public class SXSSFWorkbookWithCustomZipEntrySource extends SXSSFWorkbook {
-    private static final POILogger LOG = POILogFactory.getLogger(SXSSFWorkbookWithCustomZipEntrySource.class);
+    private static final Logger LOG = LogManager.getLogger(SXSSFWorkbookWithCustomZipEntrySource.class);
 
     public SXSSFWorkbookWithCustomZipEntrySource() {
         super(20);
@@ -60,8 +62,8 @@
     @Override
     protected SheetDataWriter createSheetDataWriter() throws IOException {
         //log values to ensure these values are accessible to subclasses
-        LOG.log(POILogger.INFO, "isCompressTempFiles: ", isCompressTempFiles());
-        LOG.log(POILogger.INFO, "SharedStringSource: ", getSharedStringSource());
+        LOG.atInfo().log("isCompressTempFiles: {}", box(isCompressTempFiles()));
+        LOG.atInfo().log("SharedStringSource: {}", getSharedStringSource());
         return new SheetDataWriterWithDecorator();
     }
 }
diff --git a/src/ooxml/java/org/apache/poi/xslf/usermodel/XMLSlideShow.java b/src/ooxml/java/org/apache/poi/xslf/usermodel/XMLSlideShow.java
index 4a355fe..1f81dc3 100644
--- a/src/ooxml/java/org/apache/poi/xslf/usermodel/XMLSlideShow.java
+++ b/src/ooxml/java/org/apache/poi/xslf/usermodel/XMLSlideShow.java
@@ -16,6 +16,7 @@
 ==================================================================== */
 package org.apache.poi.xslf.usermodel;
 
+import static org.apache.logging.log4j.util.Unbox.box;
 import static org.apache.poi.ooxml.POIXMLTypeLoader.DEFAULT_XML_OPTIONS;
 
 import java.awt.Dimension;
@@ -34,6 +35,8 @@
 import java.util.regex.Pattern;
 import java.util.stream.Stream;
 
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.apache.poi.ooxml.POIXMLDocument;
 import org.apache.poi.ooxml.POIXMLDocumentPart;
 import org.apache.poi.ooxml.POIXMLException;
@@ -50,8 +53,6 @@
 import org.apache.poi.util.Internal;
 import org.apache.poi.util.LittleEndian;
 import org.apache.poi.util.LittleEndianConsts;
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
 import org.apache.poi.util.Units;
 import org.apache.xmlbeans.XmlException;
 import org.openxmlformats.schemas.presentationml.x2006.main.CTNotesMasterIdList;
@@ -72,7 +73,7 @@
 @Beta
 public class XMLSlideShow extends POIXMLDocument
         implements SlideShow<XSLFShape, XSLFTextParagraph> {
-    private static final POILogger LOG = POILogFactory.getLogger(XMLSlideShow.class);
+    private static final Logger LOG = LogManager.getLogger(XMLSlideShow.class);
     //arbitrarily selected; may need to increase
     private static final int MAX_RECORD_LENGTH = 1_000_000;
 
@@ -167,7 +168,7 @@
                 _presentation.getSldIdLst().getSldIdList().forEach(id -> {
                     XSLFSlide sh = shIdMap.get(id.getId2());
                     if (sh == null) {
-                        LOG.log(POILogger.WARN, "Slide with r:id " + id.getId() + " was defined, but didn't exist in package, skipping");
+                        LOG.atWarn().log("Slide with r:id {} was defined, but didn't exist in package, skipping", box(id.getId()));
                     } else {
                         _slides.add(sh);
                     }
@@ -260,7 +261,7 @@
         XSLFSlideMaster sm = _masters.get(0);
         XSLFSlideLayout layout = sm.getLayout(SlideLayout.BLANK);
         if (layout == null) {
-            LOG.log(POILogger.WARN, "Blank layout was not found - defaulting to first slide layout in master");
+            LOG.atWarn().log("Blank layout was not found - defaulting to first slide layout in master");
             XSLFSlideLayout[] sl = sm.getSlideLayouts();
             if (sl.length == 0) {
                 throw new POIXMLException("SlideMaster must contain a SlideLayout.");
diff --git a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFColor.java b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFColor.java
index cafb705..c939383 100644
--- a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFColor.java
+++ b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFColor.java
@@ -22,6 +22,8 @@
 
 import javax.xml.namespace.QName;
 
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.apache.poi.ooxml.util.POIXMLUnits;
 import org.apache.poi.sl.draw.DrawPaint;
 import org.apache.poi.sl.usermodel.AbstractColorStyle;
@@ -29,8 +31,6 @@
 import org.apache.poi.sl.usermodel.PresetColor;
 import org.apache.poi.util.Beta;
 import org.apache.poi.util.Internal;
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
 import org.apache.xmlbeans.XmlCursor;
 import org.apache.xmlbeans.XmlObject;
 import org.openxmlformats.schemas.drawingml.x2006.main.CTColor;
@@ -50,7 +50,7 @@
 @Beta
 @Internal
 public class XSLFColor {
-    private static final POILogger LOGGER = POILogFactory.getLogger(XSLFColor.class);
+    private static final Logger LOGGER = LogManager.getLogger(XSLFColor.class);
     private static final QName VAL_ATTR = new QName("val");
 
     private final XmlObject _xmlObject;
@@ -187,7 +187,7 @@
     @Internal
     protected void setColor(Color color) {
         if (!(_xmlObject instanceof CTSolidColorFillProperties)) {
-            LOGGER.log(POILogger.ERROR, "XSLFColor.setColor currently only supports CTSolidColorFillProperties");
+            LOGGER.atError().log("XSLFColor.setColor currently only supports CTSolidColorFillProperties");
             return;
         }
         CTSolidColorFillProperties fill = (CTSolidColorFillProperties)_xmlObject;
diff --git a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFFreeformShape.java b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFFreeformShape.java
index 13a4842..593a4ee 100644
--- a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFFreeformShape.java
+++ b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFFreeformShape.java
@@ -27,14 +27,14 @@
 import javax.xml.stream.XMLStreamException;
 import javax.xml.stream.XMLStreamReader;
 
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.apache.poi.ooxml.POIXMLTypeLoader;
 import org.apache.poi.ooxml.util.POIXMLUnits;
 import org.apache.poi.sl.draw.geom.CustomGeometry;
 import org.apache.poi.sl.draw.geom.PresetGeometries;
 import org.apache.poi.sl.usermodel.FreeformShape;
 import org.apache.poi.util.Beta;
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
 import org.apache.poi.util.Units;
 import org.apache.xmlbeans.XmlCursor;
 import org.apache.xmlbeans.XmlObject;
@@ -62,7 +62,7 @@
 public class XSLFFreeformShape extends XSLFAutoShape
     implements FreeformShape<XSLFShape,XSLFTextParagraph> {
 
-    private static final POILogger LOG = POILogFactory.getLogger(XSLFFreeformShape.class);
+    private static final Logger LOG = LogManager.getLogger(XSLFFreeformShape.class);
 
     /*package*/ XSLFFreeformShape(CTShape shape, XSLFSheet sheet) {
         super(shape, sheet);
@@ -143,8 +143,7 @@
         try {
             staxReader.close();
         } catch (XMLStreamException e) {
-            LOG.log(POILogger.WARN,
-                    "An error occurred while closing a Custom Geometry XML Stream Reader: " + e.getMessage());
+            LOG.atWarn().log("An error occurred while closing a Custom Geometry XML Stream Reader: {}", e.getMessage());
         }
 
         return custGeo;
@@ -177,7 +176,7 @@
                         } else if (ch instanceof CTPath2DClose) {
                             addClosePath(path);
                         } else {
-                            LOG.log(POILogger.WARN, "can't handle path of type "+xo.getClass());
+                            LOG.atWarn().log("can't handle path of type {}", xo.getClass());
                         }
                     } while (cursor.toNextSibling());
                 }
diff --git a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFGraphicFrame.java b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFGraphicFrame.java
index 490908e..59109b7 100644
--- a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFGraphicFrame.java
+++ b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFGraphicFrame.java
@@ -26,6 +26,8 @@
 
 import javax.xml.namespace.QName;
 
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.apache.poi.ooxml.POIXMLException;
 import org.apache.poi.ooxml.util.POIXMLUnits;
 import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
@@ -34,8 +36,6 @@
 import org.apache.poi.sl.usermodel.GraphicalFrame;
 import org.apache.poi.sl.usermodel.ShapeType;
 import org.apache.poi.util.Beta;
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
 import org.apache.poi.util.Units;
 import org.apache.xmlbeans.XmlCursor;
 import org.apache.xmlbeans.XmlException;
@@ -51,7 +51,7 @@
 @Beta
 public class XSLFGraphicFrame extends XSLFShape implements GraphicalFrame<XSLFShape, XSLFTextParagraph> {
     private static final String DRAWINGML_CHART_URI = "http://schemas.openxmlformats.org/drawingml/2006/chart";
-    private static final POILogger LOG = POILogFactory.getLogger(XSLFGraphicFrame.class);
+    private static final Logger LOG = LogManager.getLogger(XSLFGraphicFrame.class);
 
     /*package*/ XSLFGraphicFrame(CTGraphicalObjectFrame shape, XSLFSheet sheet){
         super(shape,sheet);
@@ -285,7 +285,7 @@
         try {
             gs = CTGroupShape.Factory.parse(xo.newDomNode());
         } catch (XmlException e) {
-            LOG.log(POILogger.WARN, "Can't parse fallback picture stream of graphical frame", e);
+            LOG.atWarn().withThrowable(e).log("Can't parse fallback picture stream of graphical frame");
             return null;
         }
 
diff --git a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFGroupShape.java b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFGroupShape.java
index 0838d4e..5cf4787 100644
--- a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFGroupShape.java
+++ b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFGroupShape.java
@@ -25,14 +25,14 @@
 import java.util.Iterator;
 import java.util.List;
 
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.apache.poi.ooxml.POIXMLDocumentPart.RelationPart;
 import org.apache.poi.ooxml.util.POIXMLUnits;
 import org.apache.poi.sl.draw.DrawPictureShape;
 import org.apache.poi.sl.usermodel.GroupShape;
 import org.apache.poi.sl.usermodel.PictureData;
 import org.apache.poi.util.Beta;
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
 import org.apache.poi.util.Units;
 import org.apache.xmlbeans.XmlObject;
 import org.openxmlformats.schemas.drawingml.x2006.main.CTGroupShapeProperties;
@@ -56,7 +56,7 @@
 @Beta
 public class XSLFGroupShape extends XSLFShape
 implements XSLFShapeContainer, GroupShape<XSLFShape,XSLFTextParagraph> {
-    private static final POILogger LOG = POILogFactory.getLogger(XSLFGroupShape.class);
+    private static final Logger LOG = LogManager.getLogger(XSLFGroupShape.class);
 
     private final List<XSLFShape> _shapes;
     private final CTGroupShapeProperties _grpSpPr;
@@ -396,7 +396,7 @@
                 } else if (shape instanceof XSLFTable) {
                     newShape = createTable();
                 } else {
-                    LOG.log(POILogger.WARN, "copying of class "+shape.getClass()+" not supported.");
+                    LOG.atWarn().log("copying of class {} not supported.", shape.getClass());
                     continue;
                 }
 
diff --git a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFPictureShape.java b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFPictureShape.java
index 848c8c8..9c4fc59 100644
--- a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFPictureShape.java
+++ b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFPictureShape.java
@@ -35,6 +35,8 @@
 import javax.xml.namespace.QName;
 import javax.xml.stream.XMLStreamReader;
 
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.apache.poi.ooxml.util.POIXMLUnits;
 import org.apache.poi.ooxml.util.XPathHelper;
 import org.apache.poi.openxml4j.opc.PackagePart;
@@ -44,8 +46,6 @@
 import org.apache.poi.sl.usermodel.PictureShape;
 import org.apache.poi.sl.usermodel.Placeholder;
 import org.apache.poi.util.Beta;
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
 import org.apache.poi.util.Units;
 import org.apache.poi.xslf.draw.SVGImageRenderer;
 import org.apache.xmlbeans.XmlCursor;
@@ -70,7 +70,7 @@
 @Beta
 public class XSLFPictureShape extends XSLFSimpleShape
     implements PictureShape<XSLFShape,XSLFTextParagraph> {
-    private static final POILogger LOG = POILogFactory.getLogger(XSLFPictureShape.class);
+    private static final Logger LOG = LogManager.getLogger(XSLFPictureShape.class);
 
     private static final String MS_DML_NS = "http://schemas.microsoft.com/office/drawing/2010/main";
     private static final String MS_SVG_NS = "http://schemas.microsoft.com/office/drawing/2016/SVG/main";
@@ -357,7 +357,7 @@
         XSLFPictureShape p = (XSLFPictureShape)sh;
         String blipId = p.getBlipId();
         if (blipId == null) {
-            LOG.log(POILogger.WARN, "unable to copy invalid picture shape");
+            LOG.atWarn().log("unable to copy invalid picture shape");
             return;
         }
 
diff --git a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFPropertiesDelegate.java b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFPropertiesDelegate.java
index bce5af4..bc1aee7 100644
--- a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFPropertiesDelegate.java
+++ b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFPropertiesDelegate.java
@@ -17,9 +17,9 @@
 
 package org.apache.poi.xslf.usermodel;
 
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.apache.poi.util.Internal;
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
 import org.apache.xmlbeans.XmlCursor;
 import org.apache.xmlbeans.XmlObject;
 import org.openxmlformats.schemas.drawingml.x2006.main.CTBlipFillProperties;
@@ -50,9 +50,9 @@
  */
 @Internal
 /* package */ class XSLFPropertiesDelegate {
-    private static final POILogger LOG = POILogFactory.getLogger(XSLFPropertiesDelegate.class);
+    private static final Logger LOG = LogManager.getLogger(XSLFPropertiesDelegate.class);
 
-    
+
     public static XSLFFillProperties getFillDelegate(XmlObject props) {
         return getDelegate(XSLFFillProperties.class, props);
     }
@@ -1848,15 +1848,15 @@
         } else if (props instanceof CTTextCharacterProperties) {
             obj = new TextCharDelegate((CTTextCharacterProperties)props);
         } else {
-            LOG.log(POILogger.ERROR, props.getClass(), " is an unknown properties type");
+            LOG.atError().log("{} is an unknown properties type", props.getClass());
             return null;
         }
 
         if (clazz.isInstance(obj)) {
             return (T)obj;
         }
-        
-        LOG.log(POILogger.WARN, obj.getClass() +" doesn't implement "+ clazz);
+
+        LOG.atWarn().log("{} doesn't implement {}", obj.getClass(), clazz);
         return null;
     }
 }
diff --git a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFSheet.java b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFSheet.java
index 59945d5..1364cd7 100644
--- a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFSheet.java
+++ b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFSheet.java
@@ -16,10 +16,10 @@
 ==================================================================== */
 package org.apache.poi.xslf.usermodel;
 
+import static org.apache.logging.log4j.util.Unbox.box;
 import static org.apache.poi.ooxml.POIXMLTypeLoader.DEFAULT_XML_OPTIONS;
 
-import java.awt.Dimension;
-import java.awt.Graphics2D;
+import java.awt.*;
 import java.awt.geom.Rectangle2D;
 import java.io.IOException;
 import java.io.InputStream;
@@ -33,6 +33,8 @@
 import javax.xml.namespace.QName;
 
 import com.zaxxer.sparsebits.SparseBitSet;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.apache.poi.ooxml.POIXMLDocumentPart;
 import org.apache.poi.ooxml.POIXMLException;
 import org.apache.poi.openxml4j.opc.OPCPackage;
@@ -50,8 +52,6 @@
 import org.apache.poi.util.Beta;
 import org.apache.poi.util.IOUtils;
 import org.apache.poi.util.Internal;
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
 import org.apache.poi.util.Units;
 import org.apache.poi.xddf.usermodel.chart.XDDFChart;
 import org.apache.xmlbeans.XmlCursor;
@@ -73,7 +73,7 @@
 @Beta
 public abstract class XSLFSheet extends POIXMLDocumentPart
 implements XSLFShapeContainer, Sheet<XSLFShape,XSLFTextParagraph> {
-    private static POILogger LOG = POILogFactory.getLogger(XSLFSheet.class);
+    private static Logger LOG = LogManager.getLogger(XSLFSheet.class);
 
     private XSLFDrawing _drawing;
     private List<XSLFShape> _shapes;
@@ -122,7 +122,7 @@
     @SuppressWarnings("WeakerAccess")
     protected void registerShapeId(final int shapeId) {
         if (shapeIds.get(shapeId)) {
-            LOG.log(POILogger.WARN, "shape id "+shapeId+" has been already used.");
+            LOG.atWarn().log("shape id {} has been already used.", box(shapeId));
         }
         shapeIds.set(shapeId);
     }
@@ -130,7 +130,7 @@
     @SuppressWarnings("WeakerAccess")
     protected void deregisterShapeId(final int shapeId) {
         if (!shapeIds.get(shapeId)) {
-            LOG.log(POILogger.WARN, "shape id "+shapeId+" hasn't been registered.");
+            LOG.atWarn().log("shape id {} hasn't been registered.", box(shapeId));
         }
         shapeIds.clear(shapeId);
     }
@@ -168,7 +168,7 @@
                             CTGroupShape grp = CTGroupShape.Factory.parse(cur.newXMLStreamReader());
                             shapes.addAll(buildShapes(grp, parent));
                         } catch (XmlException e) {
-                            LOG.log(POILogger.DEBUG, "unparsable alternate content", e);
+                            LOG.atDebug().withThrowable(e).log("unparsable alternate content");
                         }
                     }
                     cur.pop();
@@ -726,7 +726,7 @@
      * @since POI 4.1.0
      */
     public void addChart(XSLFChart chart) {
-        Rectangle2D rect2D = new java.awt.Rectangle(XDDFChart.DEFAULT_X, XDDFChart.DEFAULT_Y,
+        Rectangle2D rect2D = new Rectangle(XDDFChart.DEFAULT_X, XDDFChart.DEFAULT_Y,
                 XDDFChart.DEFAULT_WIDTH, XDDFChart.DEFAULT_HEIGHT);
 
         this.addChart(chart, rect2D);
diff --git a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFSimpleShape.java b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFSimpleShape.java
index 0f4448a..f7424d1 100644
--- a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFSimpleShape.java
+++ b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFSimpleShape.java
@@ -25,6 +25,8 @@
 import javax.xml.stream.XMLStreamException;
 import javax.xml.stream.XMLStreamReader;
 
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.apache.poi.ooxml.util.POIXMLUnits;
 import org.apache.poi.openxml4j.opc.PackagePart;
 import org.apache.poi.sl.draw.DrawPaint;
@@ -44,8 +46,6 @@
 import org.apache.poi.sl.usermodel.StrokeStyle.LineCompound;
 import org.apache.poi.sl.usermodel.StrokeStyle.LineDash;
 import org.apache.poi.util.Beta;
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
 import org.apache.poi.util.Units;
 import org.apache.poi.xslf.model.PropertyFetcher;
 import org.apache.poi.xslf.usermodel.XSLFPropertiesDelegate.XSLFEffectProperties;
@@ -61,7 +61,7 @@
 public abstract class XSLFSimpleShape extends XSLFShape
     implements SimpleShape<XSLFShape,XSLFTextParagraph> {
     private static final CTOuterShadowEffect NO_SHADOW = CTOuterShadowEffect.Factory.newInstance();
-    private static final POILogger LOG = POILogFactory.getLogger(XSLFSimpleShape.class);
+    private static final Logger LOG = LogManager.getLogger(XSLFSimpleShape.class);
 
     /* package */XSLFSimpleShape(XmlObject shape, XSLFSheet sheet) {
         super(shape,sheet);
@@ -115,7 +115,7 @@
                 return ((CTShapeProperties)xo).addNewXfrm();
             } else {
                 // ... group shapes have their own getXfrm()
-                LOG.log(POILogger.WARN, getClass() +" doesn't have xfrm element.");
+                LOG.atWarn().log("{} doesn't have xfrm element.", getClass());
                 return null;
             }
         }
@@ -715,8 +715,7 @@
                 staxReader.close();
             }
             catch (XMLStreamException e) {
-                LOG.log(POILogger.WARN,
-                        "An error occurred while closing a Custom Geometry XML Stream Reader: " + e.getMessage());
+                LOG.atWarn().log("An error occurred while closing a Custom Geometry XML Stream Reader: {}", e.getMessage());
             }
         } else {
             geom = dict.get("rect");
@@ -1114,7 +1113,7 @@
     private static CTLineProperties getLn(XSLFShape shape, boolean create) {
         XmlObject pr = shape.getShapeProperties();
         if (!(pr instanceof CTShapeProperties)) {
-            LOG.log(POILogger.WARN, shape.getClass() +" doesn't have line properties");
+            LOG.atWarn().log("{} doesn't have line properties", shape.getClass());
             return null;
         }
 
diff --git a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFTextRun.java b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFTextRun.java
index 930e9ab..ea1c179 100644
--- a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFTextRun.java
+++ b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFTextRun.java
@@ -19,6 +19,8 @@
 import java.awt.Color;
 import java.util.function.Consumer;
 
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.apache.poi.common.usermodel.fonts.FontCharset;
 import org.apache.poi.common.usermodel.fonts.FontFamily;
 import org.apache.poi.common.usermodel.fonts.FontGroup;
@@ -33,8 +35,6 @@
 import org.apache.poi.sl.usermodel.TextRun;
 import org.apache.poi.util.Beta;
 import org.apache.poi.util.Internal;
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
 import org.apache.poi.util.Units;
 import org.apache.poi.xslf.model.CharacterPropertyFetcher;
 import org.apache.poi.xslf.model.CharacterPropertyFetcher.CharPropFetcher;
@@ -62,7 +62,7 @@
  */
 @Beta
 public class XSLFTextRun implements TextRun {
-    private static final POILogger LOG = POILogFactory.getLogger(XSLFTextRun.class);
+    private static final Logger LOG = LogManager.getLogger(XSLFTextRun.class);
 
     private final XmlObject _r;
     private final XSLFTextParagraph _p;
@@ -114,7 +114,7 @@
     @Override
     public void setFontColor(PaintStyle color) {
         if (!(color instanceof SolidPaint)) {
-            LOG.log(POILogger.WARN, "Currently only SolidPaint is supported!");
+            LOG.atWarn().log("Currently only SolidPaint is supported!");
             return;
         }
         SolidPaint sp = (SolidPaint)color;
diff --git a/src/ooxml/java/org/apache/poi/xssf/binary/XSSFBRelation.java b/src/ooxml/java/org/apache/poi/xssf/binary/XSSFBRelation.java
index e86fd58..94599bc 100644
--- a/src/ooxml/java/org/apache/poi/xssf/binary/XSSFBRelation.java
+++ b/src/ooxml/java/org/apache/poi/xssf/binary/XSSFBRelation.java
@@ -17,14 +17,15 @@
 
 package org.apache.poi.xssf.binary;
 
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.apache.poi.ooxml.POIXMLRelation;
 import org.apache.poi.openxml4j.opc.PackageRelationshipTypes;
 import org.apache.poi.util.Internal;
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
+import org.apache.poi.xssf.usermodel.XSSFRelation;
 
 /**
- * Need to have this mirror class of {@link org.apache.poi.xssf.usermodel.XSSFRelation}
+ * Need to have this mirror class of {@link XSSFRelation}
  * because of conflicts with regular ooxml relations.
  * If we failed to break this into a separate class, in the cases of SharedStrings and Styles,
  * 2 parts would exist, and &quot;Packages shall not contain equivalent part names...&quot;
@@ -33,7 +34,7 @@
  */
 @Internal
 public class XSSFBRelation extends POIXMLRelation {
-    private static final POILogger log = POILogFactory.getLogger(XSSFBRelation.class);
+    private static final Logger LOGGER = LogManager.getLogger(XSSFBRelation.class);
 
     static final XSSFBRelation SHARED_STRINGS_BINARY = new XSSFBRelation(
             "application/vnd.ms-excel.sharedStrings",
diff --git a/src/ooxml/java/org/apache/poi/xssf/eventusermodel/XSSFBReader.java b/src/ooxml/java/org/apache/poi/xssf/eventusermodel/XSSFBReader.java
index b1d7700..6d4c2eb 100644
--- a/src/ooxml/java/org/apache/poi/xssf/eventusermodel/XSSFBReader.java
+++ b/src/ooxml/java/org/apache/poi/xssf/eventusermodel/XSSFBReader.java
@@ -28,6 +28,8 @@
 import java.util.Set;
 
 import com.zaxxer.sparsebits.SparseBitSet;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
 import org.apache.poi.openxml4j.exceptions.OpenXML4JException;
 import org.apache.poi.openxml4j.opc.OPCPackage;
@@ -38,8 +40,6 @@
 import org.apache.poi.openxml4j.opc.PackagingURIHelper;
 import org.apache.poi.util.LittleEndian;
 import org.apache.poi.util.LittleEndianConsts;
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
 import org.apache.poi.xssf.binary.XSSFBCommentsTable;
 import org.apache.poi.xssf.binary.XSSFBParseException;
 import org.apache.poi.xssf.binary.XSSFBParser;
@@ -57,7 +57,7 @@
  */
 public class XSSFBReader extends XSSFReader {
 
-    private static final POILogger log = POILogFactory.getLogger(XSSFBReader.class);
+    private static final Logger LOGGER = LogManager.getLogger(XSSFBReader.class);
     private static final Set<String> WORKSHEET_RELS =
             Collections.unmodifiableSet(new HashSet<>(
                     Arrays.asList(new String[]{
@@ -224,7 +224,7 @@
                 tryToAddWorksheet(data);
             } catch (XSSFBParseException e) {
                 if (tryOldFormat(data)) {
-                    log.log(POILogger.WARN, "This file was written with a beta version of Excel. "+
+                    LOGGER.atWarn().log("This file was written with a beta version of Excel. "+
                             "POI will try to parse the file as a regular xlsb.");
                 } else {
                     throw e;
diff --git a/src/ooxml/java/org/apache/poi/xssf/eventusermodel/XSSFReader.java b/src/ooxml/java/org/apache/poi/xssf/eventusermodel/XSSFReader.java
index 31e20e5..db92534 100644
--- a/src/ooxml/java/org/apache/poi/xssf/eventusermodel/XSSFReader.java
+++ b/src/ooxml/java/org/apache/poi/xssf/eventusermodel/XSSFReader.java
@@ -31,6 +31,8 @@
 
 import javax.xml.parsers.ParserConfigurationException;
 
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.apache.poi.ooxml.POIXMLException;
 import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
 import org.apache.poi.openxml4j.exceptions.OpenXML4JException;
@@ -41,8 +43,6 @@
 import org.apache.poi.openxml4j.opc.PackageRelationshipCollection;
 import org.apache.poi.openxml4j.opc.PackageRelationshipTypes;
 import org.apache.poi.openxml4j.opc.PackagingURIHelper;
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
 import org.apache.poi.util.XMLHelper;
 import org.apache.poi.xssf.model.CommentsTable;
 import org.apache.poi.xssf.model.SharedStringsTable;
@@ -73,7 +73,7 @@
                             XSSFRelation.CHARTSHEET.getRelation(),
                             XSSFRelation.MACRO_SHEET_BIN.getRelation())
             ));
-    private static final POILogger LOGGER = POILogFactory.getLogger(XSSFReader.class);
+    private static final Logger LOGGER = LogManager.getLogger(XSSFReader.class);
 
     protected OPCPackage pkg;
     protected PackagePart workbookPart;
@@ -342,7 +342,7 @@
                     return new CommentsTable(commentsPart);
                 }
             } catch (InvalidFormatException|IOException e) {
-                LOGGER.log(POILogger.WARN, e);
+                LOGGER.atWarn().withThrowable(e).log("Failed to load sheet comments");
                 return null;
             }
             return null;
@@ -364,14 +364,14 @@
                     PackagePart drawingsPart = sheetPkg.getPackage().getPart(drawingsName);
                     if (drawingsPart == null) {
                         //parts can go missing; Excel ignores them silently -- TIKA-2134
-                        LOGGER.log(POILogger.WARN, "Missing drawing: " + drawingsName + ". Skipping it.");
+                        LOGGER.atWarn().log("Missing drawing: {}. Skipping it.", drawingsName);
                         continue;
                     }
                     XSSFDrawing drawing = new XSSFDrawing(drawingsPart);
                     shapes.addAll(drawing.getShapes());
                 }
             } catch (XmlException|InvalidFormatException|IOException e) {
-                LOGGER.log(POILogger.WARN, e);
+                LOGGER.atWarn().withThrowable(e).log("Failed to load shapes");
                 return null;
             }
             return shapes;
diff --git a/src/ooxml/java/org/apache/poi/xssf/eventusermodel/XSSFSheetXMLHandler.java b/src/ooxml/java/org/apache/poi/xssf/eventusermodel/XSSFSheetXMLHandler.java
index 302f22f..1cbb4d4 100644
--- a/src/ooxml/java/org/apache/poi/xssf/eventusermodel/XSSFSheetXMLHandler.java
+++ b/src/ooxml/java/org/apache/poi/xssf/eventusermodel/XSSFSheetXMLHandler.java
@@ -22,12 +22,12 @@
 import java.util.LinkedList;
 import java.util.Queue;
 
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.apache.poi.ss.usermodel.BuiltinFormats;
 import org.apache.poi.ss.usermodel.DataFormatter;
 import org.apache.poi.ss.usermodel.RichTextString;
 import org.apache.poi.ss.util.CellAddress;
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
 import org.apache.poi.xssf.model.*;
 import org.apache.poi.xssf.usermodel.XSSFCellStyle;
 import org.apache.poi.xssf.usermodel.XSSFComment;
@@ -48,7 +48,7 @@
  * you need to implement for reading information from a file.
  */
 public class XSSFSheetXMLHandler extends DefaultHandler {
-    private static final POILogger LOG = POILogFactory.getLogger(XSSFSheetXMLHandler.class);
+    private static final Logger LOG = LogManager.getLogger(XSSFSheetXMLHandler.class);
 
     /**
     * These are the different kinds of cells we support.
@@ -235,7 +235,7 @@
                 // TODO Retrieve the shared formula and tweak it to
                 //  match the current cell
                 if(formulasNotResults) {
-                    LOG.log(POILogger.WARN, "shared formulas not yet supported!");
+                    LOG.atWarn().log("shared formulas not yet supported!");
                 } /*else {
                    // It's a shared formula, so we can't get at the formula string yet
                    // However, they don't care about the formula string, so that's ok!
@@ -418,7 +418,7 @@
                    thisStr = rtss.toString();
                }
                catch (NumberFormatException ex) {
-                   LOG.log(POILogger.ERROR, "Failed to parse SST index '", sstIndex, ex);
+                   LOG.atError().withThrowable(ex).log("Failed to parse SST index '{}'", sstIndex);
                }
                break;
 
diff --git a/src/ooxml/java/org/apache/poi/xssf/extractor/XSSFBEventBasedExcelExtractor.java b/src/ooxml/java/org/apache/poi/xssf/extractor/XSSFBEventBasedExcelExtractor.java
index 9375572..817ed64 100644
--- a/src/ooxml/java/org/apache/poi/xssf/extractor/XSSFBEventBasedExcelExtractor.java
+++ b/src/ooxml/java/org/apache/poi/xssf/extractor/XSSFBEventBasedExcelExtractor.java
@@ -19,11 +19,11 @@
 import java.io.IOException;
 import java.io.InputStream;
 
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.apache.poi.openxml4j.exceptions.OpenXML4JException;
 import org.apache.poi.openxml4j.opc.OPCPackage;
 import org.apache.poi.ss.usermodel.DataFormatter;
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
 import org.apache.poi.xssf.binary.XSSFBCommentsTable;
 import org.apache.poi.xssf.binary.XSSFBHyperlinksTable;
 import org.apache.poi.xssf.binary.XSSFBSharedStringsTable;
@@ -44,7 +44,7 @@
  */
 public class XSSFBEventBasedExcelExtractor extends XSSFEventBasedExcelExtractor {
 
-    private static final POILogger LOGGER = POILogFactory.getLogger(XSSFBEventBasedExcelExtractor.class);
+    private static final Logger LOGGER = LogManager.getLogger(XSSFBEventBasedExcelExtractor.class);
 
     public static final XSSFRelation[] SUPPORTED_TYPES = new XSSFRelation[]{
             XSSFRelation.XLSB_BINARY_WORKBOOK
@@ -139,7 +139,7 @@
 
             return text.toString();
         } catch (IOException | OpenXML4JException | SAXException e) {
-            LOGGER.log(POILogger.WARN, e);
+            LOGGER.atWarn().withThrowable(e).log("Failed to load text");
             return null;
         }
     }
diff --git a/src/ooxml/java/org/apache/poi/xssf/extractor/XSSFEventBasedExcelExtractor.java b/src/ooxml/java/org/apache/poi/xssf/extractor/XSSFEventBasedExcelExtractor.java
index cfd295c..35fcb58 100644
--- a/src/ooxml/java/org/apache/poi/xssf/extractor/XSSFEventBasedExcelExtractor.java
+++ b/src/ooxml/java/org/apache/poi/xssf/extractor/XSSFEventBasedExcelExtractor.java
@@ -25,6 +25,8 @@
 
 import javax.xml.parsers.ParserConfigurationException;
 
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.apache.poi.ooxml.POIXMLDocument;
 import org.apache.poi.ooxml.POIXMLProperties;
 import org.apache.poi.ooxml.POIXMLProperties.CoreProperties;
@@ -33,9 +35,9 @@
 import org.apache.poi.ooxml.extractor.POIXMLTextExtractor;
 import org.apache.poi.openxml4j.exceptions.OpenXML4JException;
 import org.apache.poi.openxml4j.opc.OPCPackage;
+import org.apache.poi.ss.extractor.ExcelExtractor;
 import org.apache.poi.ss.usermodel.DataFormatter;
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
+import org.apache.poi.ss.usermodel.HeaderFooter;
 import org.apache.poi.util.XMLHelper;
 import org.apache.poi.xssf.eventusermodel.ReadOnlySharedStringsTable;
 import org.apache.poi.xssf.eventusermodel.XSSFReader;
@@ -59,9 +61,9 @@
  * files that uses SAX event based parsing.
  */
 public class XSSFEventBasedExcelExtractor
-    implements POIXMLTextExtractor, org.apache.poi.ss.extractor.ExcelExtractor {
+    implements POIXMLTextExtractor, ExcelExtractor {
 
-    private static final POILogger LOGGER = POILogFactory.getLogger(XSSFEventBasedExcelExtractor.class);
+    private static final Logger LOGGER = LogManager.getLogger(XSSFEventBasedExcelExtractor.class);
 
     protected final OPCPackage container;
     protected final POIXMLProperties properties;
@@ -288,7 +290,7 @@
 
             return text.toString();
         } catch (IOException | OpenXML4JException | SAXException e) {
-            LOGGER.log(POILogger.WARN, e);
+            LOGGER.atWarn().withThrowable(e).log("Failed to load text");
             return null;
         }
     }
@@ -413,7 +415,7 @@
          * they are appended in XSSFExcelExtractor.
          *
          * @see XSSFExcelExtractor#getText()
-         * @see org.apache.poi.hssf.extractor.ExcelExtractor#_extractHeaderFooter(org.apache.poi.ss.usermodel.HeaderFooter)
+         * @see org.apache.poi.hssf.extractor.ExcelExtractor#_extractHeaderFooter(HeaderFooter)
          */
         void appendHeaderText(StringBuilder buffer) {
             appendHeaderFooterText(buffer, "firstHeader");
@@ -426,7 +428,7 @@
          * they are appended in XSSFExcelExtractor.
          *
          * @see XSSFExcelExtractor#getText()
-         * @see org.apache.poi.hssf.extractor.ExcelExtractor#_extractHeaderFooter(org.apache.poi.ss.usermodel.HeaderFooter)
+         * @see org.apache.poi.hssf.extractor.ExcelExtractor#_extractHeaderFooter(HeaderFooter)
          */
         void appendFooterText(StringBuilder buffer) {
             // append the text for each footer type in the same order
diff --git a/src/ooxml/java/org/apache/poi/xssf/extractor/XSSFExportToXml.java b/src/ooxml/java/org/apache/poi/xssf/extractor/XSSFExportToXml.java
index 3904b9f..d918ae1 100644
--- a/src/ooxml/java/org/apache/poi/xssf/extractor/XSSFExportToXml.java
+++ b/src/ooxml/java/org/apache/poi/xssf/extractor/XSSFExportToXml.java
@@ -38,12 +38,12 @@
 import javax.xml.validation.SchemaFactory;
 import javax.xml.validation.Validator;
 
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.apache.poi.ooxml.util.DocumentHelper;
 import org.apache.poi.ss.usermodel.CellType;
 import org.apache.poi.ss.usermodel.DateUtil;
 import org.apache.poi.util.LocaleUtil;
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
 import org.apache.poi.util.XMLHelper;
 import org.apache.poi.xssf.usermodel.XSSFCell;
 import org.apache.poi.xssf.usermodel.XSSFMap;
@@ -79,7 +79,7 @@
  * </ul>
  */
 public class XSSFExportToXml implements Comparator<String>{
-    private static final POILogger LOG = POILogFactory.getLogger(XSSFExportToXml.class);
+    private static final Logger LOG = LogManager.getLogger(XSSFExportToXml.class);
 
 
     @FunctionalInterface
@@ -259,7 +259,7 @@
             //if no exceptions where raised, the document is valid
             return true;
         } catch(IOException e) {
-            LOG.log(POILogger.ERROR, "document is not valid", e);
+            LOG.atError().withThrowable(e).log("document is not valid");
         }
 
         return false;
@@ -546,9 +546,9 @@
         try {
             securityFeature.accept(name);
         } catch (Exception e) {
-            LOG.log(POILogger.WARN, "SchemaFactory feature unsupported", name, e);
+            LOG.atWarn().withThrowable(e).log("SchemaFactory feature ({}) unsupported", name);
         } catch (AbstractMethodError ame) {
-            LOG.log(POILogger.WARN, "Cannot set SchemaFactory feature because outdated XML parser in classpath", name, ame);
+            LOG.atWarn().withThrowable(ame).log("Cannot set SchemaFactory feature ({}) because outdated XML parser in classpath", name);
         }
     }
 }
diff --git a/src/ooxml/java/org/apache/poi/xssf/extractor/XSSFImportFromXML.java b/src/ooxml/java/org/apache/poi/xssf/extractor/XSSFImportFromXML.java
index 0295c3b..4605ee0 100644
--- a/src/ooxml/java/org/apache/poi/xssf/extractor/XSSFImportFromXML.java
+++ b/src/ooxml/java/org/apache/poi/xssf/extractor/XSSFImportFromXML.java
@@ -35,13 +35,13 @@
 import javax.xml.xpath.XPathConstants;
 import javax.xml.xpath.XPathExpressionException;
 
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.apache.poi.ooxml.util.DocumentHelper;
 import org.apache.poi.ooxml.util.XPathHelper;
 import org.apache.poi.ss.usermodel.DateUtil;
 import org.apache.poi.ss.util.CellReference;
 import org.apache.poi.util.LocaleUtil;
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
 import org.apache.poi.xssf.usermodel.XSSFCell;
 import org.apache.poi.xssf.usermodel.XSSFMap;
 import org.apache.poi.xssf.usermodel.XSSFRow;
@@ -57,6 +57,8 @@
 import org.xml.sax.InputSource;
 import org.xml.sax.SAXException;
 
+import static org.apache.logging.log4j.util.Unbox.box;
+
 /**
  * Imports data from an external XML to an XLSX according to one of the mappings
  * defined.The output XML Schema must respect this limitations:
@@ -70,7 +72,7 @@
 
     private final XSSFMap _map;
 
-    private static final POILogger LOG = POILogFactory.getLogger(XSSFImportFromXML.class);
+    private static final Logger LOG = LogManager.getLogger(XSSFImportFromXML.class);
 
     public XSSFImportFromXML(XSSFMap map) {
         _map = map;
@@ -109,10 +111,9 @@
             // result can be null if value is optional (xsd:minOccurs=0), see bugzilla 55864
             if (result != null) {
                 String textContent = result.getTextContent();
-                LOG.log(POILogger.DEBUG, "Extracting with xpath " + xpathString + " : value is '" + textContent + "'");
+                LOG.atDebug().log("Extracting with xpath {} : value is '{}'", xpathString, textContent);
                 XSSFCell cell = singleXmlCell.getReferencedCell();
-                LOG.log(POILogger.DEBUG, "Setting '" + textContent + "' to cell " + cell.getColumnIndex() + "-" + cell.getRowIndex() + " in sheet "
-                                                + cell.getSheet().getSheetName());
+                LOG.atDebug().log("Setting '{}' to cell {}-{} in sheet {}", textContent, box(cell.getColumnIndex()),box(cell.getRowIndex()),cell.getSheet().getSheetName());
                 setCellValue(textContent, cell, xmlDataType);
             }
         }
@@ -147,7 +148,7 @@
 
                     // TODO: convert the data to the cell format
                     String value = (String) xpath.evaluate(localXPath, singleNode, XPathConstants.STRING);
-                    LOG.log(POILogger.DEBUG, "Extracting with xpath " + localXPath + " : value is '" + value + "'");
+                    LOG.atDebug().log("Extracting with xpath {} : value is '{}'", localXPath, value);
                     XSSFRow row = table.getXSSFSheet().getRow(rowId);
                     if (row == null) {
                         row = table.getXSSFSheet().createRow(rowId);
@@ -157,8 +158,7 @@
                     if (cell == null) {
                         cell = row.createCell(columnId);
                     }
-                    LOG.log(POILogger.DEBUG, "Setting '" + value + "' to cell " + cell.getColumnIndex() + "-" + cell.getRowIndex() + " in sheet "
-                                                    + table.getXSSFSheet().getSheetName());
+                    LOG.atDebug().log("Setting '{}' to cell {}-{} in sheet {}", value, box(cell.getColumnIndex()),box(cell.getRowIndex()),table.getXSSFSheet().getSheetName());
                     setCellValue(value, cell, xmlColumnPr.getXmlDataType());
                 }
             }
diff --git a/src/ooxml/java/org/apache/poi/xssf/streaming/DeferredSXSSFWorkbook.java b/src/ooxml/java/org/apache/poi/xssf/streaming/DeferredSXSSFWorkbook.java
index e3c66fa..fb21c77 100644
--- a/src/ooxml/java/org/apache/poi/xssf/streaming/DeferredSXSSFWorkbook.java
+++ b/src/ooxml/java/org/apache/poi/xssf/streaming/DeferredSXSSFWorkbook.java
@@ -21,11 +21,11 @@
 import java.io.OutputStream;
 import java.util.Iterator;
 
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.apache.poi.ss.usermodel.Sheet;
 import org.apache.poi.util.Beta;
 import org.apache.poi.util.NotImplemented;
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
 import org.apache.poi.xssf.usermodel.XSSFSheet;
 import org.apache.poi.xssf.usermodel.XSSFWorkbook;
 
@@ -39,7 +39,7 @@
  */
 @Beta
 public class DeferredSXSSFWorkbook extends SXSSFWorkbook {
-    private static final POILogger LOG = POILogFactory.getLogger(DeferredSXSSFWorkbook.class);
+    private static final Logger LOG = LogManager.getLogger(DeferredSXSSFWorkbook.class);
 
     public DeferredSXSSFWorkbook() {
         this(null);
@@ -161,7 +161,7 @@
             try {
                 sxSheet.dispose();
             } catch (IOException e) {
-                LOG.log(POILogger.WARN, e);
+                LOG.atWarn().withThrowable(e).log("Failed to cleanup old sheet");
             }
         }
     }
diff --git a/src/ooxml/java/org/apache/poi/xssf/streaming/SXSSFCreationHelper.java b/src/ooxml/java/org/apache/poi/xssf/streaming/SXSSFCreationHelper.java
index 707b8ba..d18177c 100644
--- a/src/ooxml/java/org/apache/poi/xssf/streaming/SXSSFCreationHelper.java
+++ b/src/ooxml/java/org/apache/poi/xssf/streaming/SXSSFCreationHelper.java
@@ -17,6 +17,8 @@
 
 package org.apache.poi.xssf.streaming;
 
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.apache.poi.common.usermodel.HyperlinkType;
 import org.apache.poi.ss.usermodel.ClientAnchor;
 import org.apache.poi.ss.usermodel.CreationHelper;
@@ -26,8 +28,6 @@
 import org.apache.poi.ss.util.AreaReference;
 import org.apache.poi.ss.util.CellReference;
 import org.apache.poi.util.Internal;
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
 import org.apache.poi.xssf.usermodel.XSSFCreationHelper;
 import org.apache.poi.xssf.usermodel.XSSFRichTextString;
 
@@ -37,7 +37,7 @@
  *  regular XSSF Workbook
  */
 public class SXSSFCreationHelper implements CreationHelper {
-    private static final POILogger LOG = POILogFactory.getLogger(SXSSFCreationHelper.class);
+    private static final Logger LOG = LogManager.getLogger(SXSSFCreationHelper.class);
 
     private final SXSSFWorkbook wb;
     private final XSSFCreationHelper helper;
@@ -55,7 +55,7 @@
 
     @Override
     public XSSFRichTextString createRichTextString(String text) {
-        LOG.log(POILogger.INFO, "SXSSF doesn't support Rich Text Strings, any formatting information will be lost");
+        LOG.atInfo().log("SXSSF doesn't support Rich Text Strings, any formatting information will be lost");
         return new XSSFRichTextString(text);
     }
 
diff --git a/src/ooxml/java/org/apache/poi/xssf/streaming/SXSSFFormulaEvaluator.java b/src/ooxml/java/org/apache/poi/xssf/streaming/SXSSFFormulaEvaluator.java
index a846b48..67fe562 100644
--- a/src/ooxml/java/org/apache/poi/xssf/streaming/SXSSFFormulaEvaluator.java
+++ b/src/ooxml/java/org/apache/poi/xssf/streaming/SXSSFFormulaEvaluator.java
@@ -17,6 +17,8 @@
 
 package org.apache.poi.xssf.streaming;
 
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.apache.poi.ss.formula.EvaluationCell;
 import org.apache.poi.ss.formula.IStabilityClassifier;
 import org.apache.poi.ss.formula.WorkbookEvaluator;
@@ -25,16 +27,16 @@
 import org.apache.poi.ss.usermodel.CellType;
 import org.apache.poi.ss.usermodel.Row;
 import org.apache.poi.ss.usermodel.Sheet;
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
 import org.apache.poi.xssf.usermodel.BaseXSSFFormulaEvaluator;
 
+import static org.apache.logging.log4j.util.Unbox.box;
+
 /**
  * Streaming-specific Formula Evaluator, which is able to
  *  lookup cells within the current Window.
  */
 public final class SXSSFFormulaEvaluator extends BaseXSSFFormulaEvaluator {
-    private static final POILogger LOG = POILogFactory.getLogger(SXSSFFormulaEvaluator.class);
+    private static final Logger LOG = LogManager.getLogger(SXSSFFormulaEvaluator.class);
 
     private final SXSSFWorkbook wb;
 
@@ -111,7 +113,7 @@
                 int lastFlushedRowNum = ((SXSSFSheet) sheet).getLastFlushedRowNum();
                 if (lastFlushedRowNum > -1) {
                     if (! skipOutOfWindow) throw new RowFlushedException(0);
-                    LOG.log(POILogger.INFO, "Rows up to ", lastFlushedRowNum, " have already been flushed, skipping");
+                    LOG.atInfo().log("Rows up to {} have already been flushed, skipping", box(lastFlushedRowNum));
                 }
             }
 
diff --git a/src/ooxml/java/org/apache/poi/xssf/streaming/SXSSFPicture.java b/src/ooxml/java/org/apache/poi/xssf/streaming/SXSSFPicture.java
index 6711d82..a39eb59 100644
--- a/src/ooxml/java/org/apache/poi/xssf/streaming/SXSSFPicture.java
+++ b/src/ooxml/java/org/apache/poi/xssf/streaming/SXSSFPicture.java
@@ -20,6 +20,8 @@
 import java.awt.Dimension;
 import java.io.IOException;
 
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.apache.poi.openxml4j.opc.PackagePart;
 import org.apache.poi.ss.usermodel.Picture;
 import org.apache.poi.ss.usermodel.Row;
@@ -28,8 +30,6 @@
 import org.apache.poi.ss.usermodel.Workbook;
 import org.apache.poi.ss.util.ImageUtils;
 import org.apache.poi.util.Internal;
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
 import org.apache.poi.util.Units;
 import org.apache.poi.xssf.usermodel.XSSFAnchor;
 import org.apache.poi.xssf.usermodel.XSSFClientAnchor;
@@ -50,7 +50,7 @@
  * The main change is to access the rows in the SXSSF sheet, not the always empty rows in the XSSF sheet when checking the row heights.
  */
 public final class SXSSFPicture implements Picture {
-    private static final POILogger LOG = POILogFactory.getLogger(SXSSFPicture.class);
+    private static final Logger LOG = LogManager.getLogger(SXSSFPicture.class);
     /**
      * Column width measured as the number of characters of the maximum digit width of the
      * numbers 0, 1, 2, ..., 9 as rendered in the normal style's font. There are 4 pixels of margin
@@ -109,7 +109,7 @@
         XSSFClientAnchor anchor = getClientAnchor();
         XSSFClientAnchor pref = getPreferredSize(scale);
         if (anchor == null || pref == null) {
-            LOG.log(POILogger.WARN, "picture is not anchored via client anchor - ignoring resize call");
+            LOG.atWarn().log("picture is not anchored via client anchor - ignoring resize call");
             return;
         }
 
@@ -144,7 +144,7 @@
     public XSSFClientAnchor getPreferredSize(double scale){
         XSSFClientAnchor anchor = getClientAnchor();
         if (anchor == null) {
-            LOG.log(POILogger.WARN, "picture is not anchored via client anchor - ignoring resize call");
+            LOG.atWarn().log("picture is not anchored via client anchor - ignoring resize call");
             return null;
         }
 
@@ -222,7 +222,7 @@
             return ImageUtils.getImageDimension(part.getInputStream(), type);
         } catch (IOException e){
             //return a "singulariry" if ImageIO failed to read the image
-            LOG.log(POILogger.WARN, e);
+            LOG.atWarn().withThrowable(e).log("Failed to read image");
             return new Dimension();
         }
     }
diff --git a/src/ooxml/java/org/apache/poi/xssf/streaming/SXSSFWorkbook.java b/src/ooxml/java/org/apache/poi/xssf/streaming/SXSSFWorkbook.java
index 42fc9c0..a4a9a43 100644
--- a/src/ooxml/java/org/apache/poi/xssf/streaming/SXSSFWorkbook.java
+++ b/src/ooxml/java/org/apache/poi/xssf/streaming/SXSSFWorkbook.java
@@ -36,6 +36,8 @@
 import org.apache.commons.compress.archivers.zip.Zip64Mode;
 import org.apache.commons.compress.archivers.zip.ZipArchiveEntry;
 import org.apache.commons.compress.archivers.zip.ZipArchiveOutputStream;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.apache.poi.openxml4j.opc.OPCPackage;
 import org.apache.poi.openxml4j.util.ZipArchiveThresholdInputStream;
 import org.apache.poi.openxml4j.util.ZipEntrySource;
@@ -50,6 +52,7 @@
 import org.apache.poi.ss.usermodel.Font;
 import org.apache.poi.ss.usermodel.Name;
 import org.apache.poi.ss.usermodel.PictureData;
+import org.apache.poi.ss.usermodel.Row;
 import org.apache.poi.ss.usermodel.Row.MissingCellPolicy;
 import org.apache.poi.ss.usermodel.Sheet;
 import org.apache.poi.ss.usermodel.SheetVisibility;
@@ -58,8 +61,6 @@
 import org.apache.poi.util.IOUtils;
 import org.apache.poi.util.Internal;
 import org.apache.poi.util.NotImplemented;
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
 import org.apache.poi.util.Removal;
 import org.apache.poi.util.TempFile;
 import org.apache.poi.xssf.model.SharedStringsTable;
@@ -102,7 +103,7 @@
      * via {@link SXSSFSheet#getRow} anymore.
      */
     public static final int DEFAULT_WINDOW_SIZE = 100;
-    private static final POILogger LOG = POILogFactory.getLogger(SXSSFWorkbook.class);
+    private static final Logger LOG = LogManager.getLogger(SXSSFWorkbook.class);
 
     protected final XSSFWorkbook _wb;
 
@@ -839,7 +840,7 @@
         try {
             sxSheet.dispose();
         } catch (IOException e) {
-            LOG.log(POILogger.WARN, e);
+            LOG.atWarn().withThrowable(e).log("Failed to dispose old sheet");
         }
     }
 
@@ -935,9 +936,7 @@
                 SheetDataWriter _writer = sheet.getSheetDataWriter();
                 if (_writer != null) _writer.close();
             } catch (IOException e) {
-                LOG.log(POILogger.WARN,
-                        "An exception occurred while closing sheet data writer for sheet "
-                                + sheet.getSheetName() + ".", e);
+                LOG.atWarn().withThrowable(e).log("An exception occurred while closing sheet data writer for sheet {}.", sheet.getSheetName());
             }
         }
 
@@ -998,7 +997,7 @@
             try {
                 success = sheet.dispose() && success;
             } catch (IOException e) {
-                LOG.log(POILogger.WARN, e);
+                LOG.atWarn().withThrowable(e).log("Failed to dispose sheet");
                 success = false;
             }
         }
@@ -1139,7 +1138,7 @@
      *  getting missing or blank cells from a row.
      *
      * This will then apply to all calls to
-     *  {@link org.apache.poi.ss.usermodel.Row#getCell(int)}. See
+     *  {@link Row#getCell(int)}. See
      *  {@link MissingCellPolicy}
      */
     @Override
diff --git a/src/ooxml/java/org/apache/poi/xssf/streaming/SheetDataWriter.java b/src/ooxml/java/org/apache/poi/xssf/streaming/SheetDataWriter.java
index 93f0b50..f72b6a2 100644
--- a/src/ooxml/java/org/apache/poi/xssf/streaming/SheetDataWriter.java
+++ b/src/ooxml/java/org/apache/poi/xssf/streaming/SheetDataWriter.java
@@ -32,13 +32,13 @@
 import java.nio.charset.StandardCharsets;
 import java.util.Iterator;
 
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.apache.poi.ss.usermodel.Cell;
 import org.apache.poi.ss.usermodel.CellStyle;
 import org.apache.poi.ss.usermodel.CellType;
 import org.apache.poi.ss.usermodel.FormulaError;
 import org.apache.poi.ss.util.CellReference;
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
 import org.apache.poi.util.StringCodepointsIterable;
 import org.apache.poi.util.TempFile;
 import org.apache.poi.xssf.model.SharedStringsTable;
@@ -52,7 +52,7 @@
  * so that it was renamed to "SheetDataWriter"
  */
 public class SheetDataWriter implements Closeable {
-    private static final POILogger LOG = POILogFactory.getLogger(SheetDataWriter.class);
+    private static final Logger LOG = LogManager.getLogger(SheetDataWriter.class);
 
     private final File _fd;
     protected final Writer _out;
@@ -186,7 +186,7 @@
     @Override
     protected void finalize() throws Throwable {
         if (_fd.exists() && !_fd.delete()) {
-            LOG.log(POILogger.ERROR, "Can't delete temporary encryption file: ", _fd);
+            LOG.atError().log("Can't delete temporary encryption file: {}", _fd);
         }
     }
 
diff --git a/src/ooxml/java/org/apache/poi/xssf/streaming/StreamingSheetWriter.java b/src/ooxml/java/org/apache/poi/xssf/streaming/StreamingSheetWriter.java
index 065f585..ef5e6c3 100644
--- a/src/ooxml/java/org/apache/poi/xssf/streaming/StreamingSheetWriter.java
+++ b/src/ooxml/java/org/apache/poi/xssf/streaming/StreamingSheetWriter.java
@@ -25,9 +25,9 @@
 import java.io.OutputStreamWriter;
 import java.io.Writer;
 
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.apache.poi.util.Beta;
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
 
 /**
  * Unlike SheetDataWriter, this writer does not create a temporary file, it writes data directly
@@ -36,7 +36,7 @@
  */
 @Beta
 public class StreamingSheetWriter extends SheetDataWriter {
-    private static final POILogger LOG = POILogFactory.getLogger(StreamingSheetWriter.class);
+    private static final Logger LOG = LogManager.getLogger(StreamingSheetWriter.class);
 
     public StreamingSheetWriter() throws IOException {
         throw new RuntimeException("StreamingSheetWriter requires OutputStream");
@@ -44,7 +44,7 @@
 
     public StreamingSheetWriter(OutputStream out) throws IOException {
         super(createWriter(out));
-        LOG.log(POILogger.DEBUG, "Preparing SSXSSF sheet writer");
+        LOG.atDebug().log("Preparing SSXSSF sheet writer");
     }
 
     @Override
diff --git a/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFDrawing.java b/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFDrawing.java
index fadb24d..5016971 100644
--- a/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFDrawing.java
+++ b/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFDrawing.java
@@ -28,6 +28,8 @@
 
 import javax.xml.namespace.QName;
 
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.apache.poi.ooxml.POIXMLDocumentPart;
 import org.apache.poi.ooxml.POIXMLException;
 import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
@@ -42,8 +44,6 @@
 import org.apache.poi.ss.util.CellAddress;
 import org.apache.poi.ss.util.ImageUtils;
 import org.apache.poi.util.Internal;
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
 import org.apache.poi.util.Units;
 import org.apache.poi.xssf.model.CommentsTable;
 import org.apache.xmlbeans.XmlCursor;
@@ -76,7 +76,7 @@
  * Represents a SpreadsheetML drawing
  */
 public final class XSSFDrawing extends POIXMLDocumentPart implements Drawing<XSSFShape> {
-    private static final POILogger LOG = POILogFactory.getLogger(XSSFDrawing.class);
+    private static final Logger LOG = LogManager.getLogger(XSSFDrawing.class);
 
     /**
      * Root element of the SpreadsheetML Drawing part
@@ -90,7 +90,7 @@
     /**
      * Create a new SpreadsheetML drawing
      *
-     * @see org.apache.poi.xssf.usermodel.XSSFSheet#createDrawingPatriarch()
+     * @see XSSFSheet#createDrawingPatriarch()
      */
     protected XSSFDrawing() {
         super();
@@ -191,7 +191,7 @@
      * @param pictureIndex
      *            the index of the picture in the workbook collection of
      *            pictures,
-     *            {@link org.apache.poi.xssf.usermodel.XSSFWorkbook#getAllPictures()}
+     *            {@link XSSFWorkbook#getAllPictures()}
      *            .
      *
      * @return the newly created picture shape.
@@ -226,7 +226,7 @@
      *            the client anchor describes how this chart is attached to the
      *            sheet.
      * @return the newly created chart
-     * @see org.apache.poi.xssf.usermodel.XSSFDrawing#createChart(ClientAnchor)
+     * @see XSSFDrawing#createChart(ClientAnchor)
      */
     public XSSFChart createChart(XSSFClientAnchor anchor) {
         int chartNumber = getPackagePart().getPackage().getPartsByContentType(XSSFRelation.CHART.getContentType())
@@ -279,7 +279,7 @@
      * Add the indexed picture to this drawing relations
      *
      * @param pictureIndex the index of the picture in the workbook collection of pictures,
-     *            {@link org.apache.poi.xssf.usermodel.XSSFWorkbook#getAllPictures()}           .
+     *            {@link XSSFWorkbook#getAllPictures()}           .
      */
     protected PackageRelationship addPictureReference(int pictureIndex) {
         XSSFWorkbook wb = (XSSFWorkbook) getParent().getParent();
@@ -639,8 +639,7 @@
                         } else if (obj instanceof CTGroupShape) {
                             shape = new XSSFShapeGroup(this, (CTGroupShape) obj);
                         } else if (obj instanceof XmlAnyTypeImpl) {
-                            LOG.log(POILogger.WARN,
-                                "trying to parse AlternateContent, this unlinks the returned Shapes from the underlying xml content, so those shapes can't be used to modify the drawing, i.e. modifications will be ignored!");
+                            LOG.atWarn().log("trying to parse AlternateContent, this unlinks the returned Shapes from the underlying xml content, so those shapes can't be used to modify the drawing, i.e. modifications will be ignored!");
 
                             // XmlAnyTypeImpl is returned for AlternateContent
                             // parts, which might contain a CTDrawing
@@ -657,7 +656,7 @@
                                     addShapes(cur2, lst);
                                 }
                             } catch (XmlException e) {
-                                LOG.log(POILogger.WARN, "unable to parse CTDrawing in alternate content.", e);
+                                LOG.atWarn().withThrowable(e).log("unable to parse CTDrawing in alternate content.");
                             } finally {
                                 if (cur2 != null) {
                                     cur2.dispose();
diff --git a/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFObjectData.java b/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFObjectData.java
index 0544800..16d0408 100644
--- a/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFObjectData.java
+++ b/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFObjectData.java
@@ -23,6 +23,8 @@
 
 import javax.xml.namespace.QName;
 
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.apache.poi.ooxml.POIXMLDocumentPart;
 import org.apache.poi.ooxml.POIXMLException;
 import org.apache.poi.openxml4j.opc.PackagePart;
@@ -32,8 +34,6 @@
 import org.apache.poi.poifs.filesystem.POIFSFileSystem;
 import org.apache.poi.ss.usermodel.ObjectData;
 import org.apache.poi.util.IOUtils;
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
 import org.apache.xmlbeans.XmlCursor;
 import org.openxmlformats.schemas.drawingml.x2006.main.CTNonVisualDrawingProps;
 import org.openxmlformats.schemas.drawingml.x2006.main.CTOfficeArtExtension;
@@ -52,8 +52,8 @@
  * Represents binary object (i.e. OLE) data stored in the file.  Eg. A GIF, JPEG etc...
  */
 public class XSSFObjectData extends XSSFSimpleShape implements ObjectData {
-    private static final POILogger LOG = POILogFactory.getLogger(XSSFObjectData.class);
-    
+    private static final Logger LOG = LogManager.getLogger(XSSFObjectData.class);
+
     /**
      * A default instance of CTShape used for creating new shapes.
      */
@@ -163,7 +163,7 @@
             is = FileMagic.prepareToCheckMagic(is);
             return FileMagic.valueOf(is) == FileMagic.OLE2;
         } catch (IOException e) {
-            LOG.log(POILogger.WARN, "can't determine if directory entry exists", e);
+            LOG.atWarn().withThrowable(e).log("can't determine if directory entry exists");
             return false;
         } finally {
             IOUtils.closeQuietly(is);
diff --git a/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFPicture.java b/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFPicture.java
index 1055d6b..86f3bd9 100644
--- a/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFPicture.java
+++ b/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFPicture.java
@@ -20,14 +20,14 @@
 import java.awt.Dimension;
 import java.io.IOException;
 
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.apache.poi.openxml4j.opc.PackagePart;
 import org.apache.poi.openxml4j.opc.PackageRelationship;
 import org.apache.poi.ss.usermodel.Picture;
 import org.apache.poi.ss.usermodel.Workbook;
 import org.apache.poi.ss.util.ImageUtils;
 import org.apache.poi.util.Internal;
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
 import org.openxmlformats.schemas.drawingml.x2006.main.CTBlipFillProperties;
 import org.openxmlformats.schemas.drawingml.x2006.main.CTNonVisualDrawingProps;
 import org.openxmlformats.schemas.drawingml.x2006.main.CTNonVisualPictureProperties;
@@ -46,7 +46,7 @@
  * @author Yegor Kozlov
  */
 public final class XSSFPicture extends XSSFShape implements Picture {
-    private static final POILogger LOG = POILogFactory.getLogger(XSSFPicture.class);
+    private static final Logger LOG = LogManager.getLogger(XSSFPicture.class);
 
     /**
      * Column width measured as the number of characters of the maximum digit width of the
@@ -170,15 +170,15 @@
      * </p>
      *
      * @param scaleX the amount by which the image width is multiplied relative to the original width,
-     *  when set to {@link java.lang.Double#MAX_VALUE} the width of the embedded image is used
+     *  when set to {@link Double#MAX_VALUE} the width of the embedded image is used
      * @param scaleY the amount by which the image height is multiplied relative to the original height,
-     *  when set to {@link java.lang.Double#MAX_VALUE} the height of the embedded image is used
+     *  when set to {@link Double#MAX_VALUE} the height of the embedded image is used
      */
     public void resize(double scaleX, double scaleY){
         XSSFClientAnchor anchor = getClientAnchor();
         XSSFClientAnchor pref = getPreferredSize(scaleX,scaleY);
         if (anchor == null || pref == null) {
-            LOG.log(POILogger.WARN, "picture is not anchored via client anchor - ignoring resize call");
+            LOG.atWarn().log("picture is not anchored via client anchor - ignoring resize call");
             return;
         }
 
@@ -242,7 +242,7 @@
             return ImageUtils.getImageDimension(part.getInputStream(), type);
         } catch (IOException e){
             //return a "singulariry" if ImageIO failed to read the image
-            LOG.log(POILogger.WARN, e);
+            LOG.atWarn().withThrowable(e).log("Failed to read image");
             return new Dimension();
         }
     }
diff --git a/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFSheet.java b/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFSheet.java
index b93f165..0e54838 100644
--- a/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFSheet.java
+++ b/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFSheet.java
@@ -41,6 +41,8 @@
 import javax.xml.stream.XMLStreamException;
 import javax.xml.stream.XMLStreamReader;
 
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.apache.poi.ooxml.POIXMLDocumentPart;
 import org.apache.poi.ooxml.POIXMLException;
 import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
@@ -62,12 +64,14 @@
 import org.apache.poi.ss.usermodel.DataValidationHelper;
 import org.apache.poi.ss.usermodel.Font;
 import org.apache.poi.ss.usermodel.Footer;
+import org.apache.poi.ss.usermodel.FormulaEvaluator;
 import org.apache.poi.ss.usermodel.Header;
 import org.apache.poi.ss.usermodel.IgnoredErrorType;
 import org.apache.poi.ss.usermodel.Name;
 import org.apache.poi.ss.usermodel.Row;
 import org.apache.poi.ss.usermodel.Sheet;
 import org.apache.poi.ss.usermodel.Table;
+import org.apache.poi.ss.usermodel.Workbook;
 import org.apache.poi.ss.util.AreaReference;
 import org.apache.poi.ss.util.CellAddress;
 import org.apache.poi.ss.util.CellRangeAddress;
@@ -78,8 +82,6 @@
 import org.apache.poi.ss.util.SheetUtil;
 import org.apache.poi.util.Beta;
 import org.apache.poi.util.Internal;
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
 import org.apache.poi.util.Units;
 import org.apache.poi.xssf.model.CommentsTable;
 import org.apache.poi.xssf.usermodel.XSSFPivotTable.PivotTableReferenceConfigurator;
@@ -103,7 +105,7 @@
  * </p>
  */
 public class XSSFSheet extends POIXMLDocumentPart implements Sheet  {
-    private static final POILogger LOG = POILogFactory.getLogger(XSSFSheet.class);
+    private static final Logger LOG = LogManager.getLogger(XSSFSheet.class);
 
     private static final double DEFAULT_ROW_HEIGHT = 15.0;
     private static final double DEFAULT_MARGIN_HEADER = 0.3;
@@ -139,7 +141,7 @@
     /**
      * Creates new XSSFSheet   - called by XSSFWorkbook to create a sheet from scratch.
      *
-     * @see org.apache.poi.xssf.usermodel.XSSFWorkbook#createSheet()
+     * @see XSSFWorkbook#createSheet()
      */
     protected XSSFSheet() {
         super();
@@ -556,7 +558,7 @@
                     break;
                 }
             }
-            LOG.log(POILogger.ERROR, "Can't find drawing with id=", ctDrawing.getId(), " in the list of the sheet's relationships");
+            LOG.atError().log("Can't find drawing with id={} in the list of the sheet's relationships", ctDrawing.getId());
         }
         return null;
     }
@@ -628,7 +630,7 @@
                 }
             }
             if(drawing == null){
-                LOG.log(POILogger.ERROR, "Can't find VML drawing with id=", id, " in the list of the sheet's relationships");
+                LOG.atError().log("Can't find VML drawing with id={} in the list of the sheet's relationships", id);
             }
         }
         return drawing;
@@ -720,7 +722,7 @@
      *
      * @param rownum  row number
      * @return High level {@link XSSFRow} object representing a row in the sheet
-     * @see #removeRow(org.apache.poi.ss.usermodel.Row)
+     * @see #removeRow(Row)
      */
     @Override
     public XSSFRow createRow(int rownum) {
@@ -766,10 +768,10 @@
      * @param leftmostColumn   Left column visible in right pane.
      * @param activePane    Active pane.  One of: PANE_LOWER_RIGHT,
      *                      PANE_UPPER_RIGHT, PANE_LOWER_LEFT, PANE_UPPER_LEFT
-     * @see org.apache.poi.ss.usermodel.Sheet#PANE_LOWER_LEFT
-     * @see org.apache.poi.ss.usermodel.Sheet#PANE_LOWER_RIGHT
-     * @see org.apache.poi.ss.usermodel.Sheet#PANE_UPPER_LEFT
-     * @see org.apache.poi.ss.usermodel.Sheet#PANE_UPPER_RIGHT
+     * @see Sheet#PANE_LOWER_LEFT
+     * @see Sheet#PANE_LOWER_RIGHT
+     * @see Sheet#PANE_UPPER_LEFT
+     * @see Sheet#PANE_UPPER_RIGHT
      */
     @Override
     public void createSplitPane(int xSplitPos, int ySplitPos, int leftmostColumn, int topRow, int activePane) {
@@ -2026,20 +2028,20 @@
      * when the workbook is opened.
      *
      *  <p>
-     *  Calculating the formula values with {@link org.apache.poi.ss.usermodel.FormulaEvaluator} is the
+     *  Calculating the formula values with {@link FormulaEvaluator} is the
      *  recommended solution, but this may be used for certain cases where
      *  evaluation in POI is not possible.
      *  </p>
      *
      *  <p>
      *  It is recommended to force recalcuation of formulas on workbook level using
-     *  {@link org.apache.poi.ss.usermodel.Workbook#setForceFormulaRecalculation(boolean)}
+     *  {@link Workbook#setForceFormulaRecalculation(boolean)}
      *  to ensure that all cross-worksheet formuals and external dependencies are updated.
      *  </p>
      * @param value true if the application will perform a full recalculation of
      * this worksheet values when the workbook is opened
      *
-     * @see org.apache.poi.ss.usermodel.Workbook#setForceFormulaRecalculation(boolean)
+     * @see Workbook#setForceFormulaRecalculation(boolean)
      */
     @Override
     public void setForceFormulaRecalculation(boolean value) {
@@ -4676,12 +4678,12 @@
                         }
                         coo = coos.getOleObjectArray(0);
                     } catch (XmlException e) {
-                        LOG.log(POILogger.INFO, "can't parse CTOleObjects", e);
+                        LOG.atInfo().withThrowable(e).log("can't parse CTOleObjects");
                     } finally {
                         try {
                             reader.close();
                         } catch (XMLStreamException e) {
-                            LOG.log(POILogger.INFO, "can't close reader", e);
+                            LOG.atInfo().withThrowable(e).log("can't close reader");
                         }
                     }
                 }
diff --git a/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFTableStyle.java b/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFTableStyle.java
index b51a92d..852f91c 100644
--- a/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFTableStyle.java
+++ b/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFTableStyle.java
@@ -22,11 +22,11 @@
 import java.util.List;
 import java.util.Map;
 
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.apache.poi.ss.usermodel.DifferentialStyleProvider;
 import org.apache.poi.ss.usermodel.TableStyle;
 import org.apache.poi.ss.usermodel.TableStyleType;
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
 import org.apache.xmlbeans.XmlCursor;
 import org.apache.xmlbeans.XmlException;
 import org.apache.xmlbeans.XmlObject;
@@ -41,7 +41,7 @@
  * Also used for built-in styles via dummy XML generated from presetTableStyles.xml.
  */
 public class XSSFTableStyle implements TableStyle {
-    private static final POILogger LOG = POILogFactory.getLogger(XSSFTableStyle.class);
+    private static final Logger LOG = LogManager.getLogger(XSSFTableStyle.class);
 
     private final String name;
     private final int index;
@@ -79,7 +79,7 @@
                     }
                     if (dxf != null) dxfList.add(dxf);
                 } catch (XmlException e) {
-                    LOG.log(POILogger.WARN, "Error parsing XSSFTableStyle", e);
+                    LOG.atWarn().withThrowable(e).log("Error parsing XSSFTableStyle");
                 }
             }
         }
diff --git a/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFWorkbook.java b/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFWorkbook.java
index e390bca..17ebf32 100644
--- a/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFWorkbook.java
+++ b/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFWorkbook.java
@@ -43,6 +43,8 @@
 
 import org.apache.commons.collections4.ListValuedMap;
 import org.apache.commons.collections4.multimap.ArrayListValuedHashMap;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.apache.poi.hpsf.ClassIDPredefined;
 import org.apache.poi.ooxml.POIXMLDocument;
 import org.apache.poi.ooxml.POIXMLDocumentPart;
@@ -68,6 +70,7 @@
 import org.apache.poi.ss.formula.udf.AggregatingUDFFinder;
 import org.apache.poi.ss.formula.udf.IndexedUDFFinder;
 import org.apache.poi.ss.formula.udf.UDFFinder;
+import org.apache.poi.ss.usermodel.DataFormat;
 import org.apache.poi.ss.usermodel.Date1904Support;
 import org.apache.poi.ss.usermodel.Name;
 import org.apache.poi.ss.usermodel.Row;
@@ -81,8 +84,6 @@
 import org.apache.poi.util.IOUtils;
 import org.apache.poi.util.Internal;
 import org.apache.poi.util.NotImplemented;
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
 import org.apache.poi.util.Removal;
 import org.apache.poi.xssf.XLSBUnsupportedException;
 import org.apache.poi.xssf.model.CalculationChain;
@@ -200,7 +201,7 @@
     /**
      * The policy to apply in the event of missing or
      *  blank cells when fetching from a row.
-     * See {@link org.apache.poi.ss.usermodel.Row.MissingCellPolicy}
+     * See {@link MissingCellPolicy}
      */
     private MissingCellPolicy _missingCellPolicy = MissingCellPolicy.RETURN_NULL_AND_BLANK;
 
@@ -214,7 +215,7 @@
      */
     private List<XSSFPictureData> pictures;
 
-    private static final POILogger LOG = POILogFactory.getLogger(XSSFWorkbook.class);
+    private static final Logger LOG = LogManager.getLogger(XSSFWorkbook.class);
 
     /**
      * cached instance of XSSFCreationHelper for this workbook
@@ -415,7 +416,7 @@
                 for (CTExternalReference er : this.workbook.getExternalReferences().getExternalReferenceArray()) {
                     ExternalLinksTable el = elIdMap.get(er.getId());
                     if(el == null) {
-                        LOG.log(POILogger.WARN, "ExternalLinksTable with r:id ", er.getId(), " was defined, but didn't exist in package, skipping");
+                        LOG.atWarn().log("ExternalLinksTable with r:id {} was defined, but didn't exist in package, skipping", er.getId());
                         continue;
                     }
                     externalLinks.add(el);
@@ -436,8 +437,7 @@
     public void parseSheet(Map<String, XSSFSheet> shIdMap, CTSheet ctSheet) {
         XSSFSheet sh = shIdMap.get(ctSheet.getId());
         if(sh == null) {
-            LOG.log(POILogger.WARN, "Sheet with name ", ctSheet.getName(), " and r:id ",
-                    ctSheet.getId(), " was defined, but didn't exist in package, skipping");
+            LOG.atWarn().log("Sheet with name {} and r:id {} was defined, but didn't exist in package, skipping", ctSheet.getName(), ctSheet.getId());
             return;
         }
         sh.sheet = ctSheet;
@@ -649,11 +649,11 @@
         }
         CTWorksheet ct = clonedSheet.getCTWorksheet();
         if(ct.isSetLegacyDrawing()) {
-            LOG.log(POILogger.WARN, "Cloning sheets with comments is not yet supported.");
+            LOG.atWarn().log("Cloning sheets with comments is not yet supported.");
             ct.unsetLegacyDrawing();
         }
         if (ct.isSetPageSetup()) {
-            LOG.log(POILogger.WARN, "Cloning sheets with page setup is not yet supported.");
+            LOG.atWarn().log("Cloning sheets with page setup is not yet supported.");
             ct.unsetPageSetup();
         }
 
@@ -748,7 +748,7 @@
      * Returns the workbook's data format table (a factory for creating data format strings).
      *
      * @return the XSSFDataFormat object
-     * @see org.apache.poi.ss.usermodel.DataFormat
+     * @see DataFormat
      */
     @Override
     public XSSFDataFormat createDataFormat() {
@@ -839,14 +839,14 @@
      * </p>
      *
      * <p>
-     * See {@link org.apache.poi.ss.util.WorkbookUtil#createSafeSheetName(String nameProposal)}
+     * See {@link WorkbookUtil#createSafeSheetName(String nameProposal)}
      *      for a safe way to create valid names
      * </p>
      * @param sheetname  sheetname to set for the sheet.
      * @return Sheet representing the new sheet.
      * @throws IllegalArgumentException if the name is null or invalid
      *  or workbook already contains a sheet with this name
-     * @see org.apache.poi.ss.util.WorkbookUtil#createSafeSheetName(String nameProposal)
+     * @see WorkbookUtil#createSafeSheetName(String nameProposal)
      */
     @Override
     public XSSFSheet createSheet(String sheetname) {
@@ -1550,7 +1550,7 @@
      * @throws IllegalArgumentException if the name is null or invalid
      *  or workbook already contains a sheet with this name
      * @see #createSheet(String)
-     * @see org.apache.poi.ss.util.WorkbookUtil#createSafeSheetName(String nameProposal)
+     * @see WorkbookUtil#createSafeSheetName(String nameProposal)
      */
     @Override
     public void setSheetName(int sheetIndex, String sheetname) {
diff --git a/src/ooxml/java/org/apache/poi/xssf/usermodel/helpers/XSSFColumnShifter.java b/src/ooxml/java/org/apache/poi/xssf/usermodel/helpers/XSSFColumnShifter.java
index 8532c8b..2acc895 100644
--- a/src/ooxml/java/org/apache/poi/xssf/usermodel/helpers/XSSFColumnShifter.java
+++ b/src/ooxml/java/org/apache/poi/xssf/usermodel/helpers/XSSFColumnShifter.java
@@ -17,11 +17,11 @@
 
 package org.apache.poi.xssf.usermodel.helpers;
 
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.apache.poi.ss.formula.FormulaShifter;
 import org.apache.poi.ss.usermodel.helpers.ColumnShifter;
 import org.apache.poi.util.Beta;
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
 import org.apache.poi.xssf.usermodel.XSSFSheet;
 
 /**
@@ -33,7 +33,7 @@
 // {@link org.apache.poi.hssf.usermodel.helpers.HSSFColumnShifter}
 @Beta
 public final class XSSFColumnShifter extends ColumnShifter {
-    private static final POILogger LOG = POILogFactory.getLogger(XSSFColumnShifter.class);
+    private static final Logger LOG = LogManager.getLogger(XSSFColumnShifter.class);
 
     public XSSFColumnShifter(XSSFSheet sh) {
         super(sh);
diff --git a/src/ooxml/java/org/apache/poi/xssf/usermodel/helpers/XSSFRowColShifter.java b/src/ooxml/java/org/apache/poi/xssf/usermodel/helpers/XSSFRowColShifter.java
index b15910b..298fa3f 100644
--- a/src/ooxml/java/org/apache/poi/xssf/usermodel/helpers/XSSFRowColShifter.java
+++ b/src/ooxml/java/org/apache/poi/xssf/usermodel/helpers/XSSFRowColShifter.java
@@ -17,6 +17,8 @@
 
 package org.apache.poi.xssf.usermodel.helpers;
 
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.apache.poi.ss.formula.FormulaShifter;
 import org.apache.poi.ss.formula.FormulaParser;
 import org.apache.poi.ss.formula.FormulaType;
@@ -27,14 +29,14 @@
 import org.apache.poi.ss.usermodel.helpers.BaseRowColShifter;
 import org.apache.poi.ss.util.CellRangeAddress;
 import org.apache.poi.util.Internal;
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
 import org.apache.poi.xssf.usermodel.*;
 import org.openxmlformats.schemas.spreadsheetml.x2006.main.*;
 
 import java.util.ArrayList;
 import java.util.List;
 
+import static org.apache.logging.log4j.util.Unbox.box;
+
 /**
  * Class for code common to {@link XSSFRowShifter} and {@link XSSFColumnShifter}
  *
@@ -42,7 +44,7 @@
  */
 @Internal
 /*private*/ final class XSSFRowColShifter {
-    private static final POILogger LOG = POILogFactory.getLogger(XSSFRowColShifter.class);
+    private static final Logger LOG = LogManager.getLogger(XSSFRowColShifter.class);
 
     private XSSFRowColShifter() { /*no instances for static classes*/}
 
@@ -151,7 +153,7 @@
             return shiftedFmla;
         } catch (FormulaParseException fpe) {
             // Log, but don't change, rather than breaking
-            LOG.log(POILogger.WARN, "Error shifting formula on row ", row.getRowNum(), fpe);
+            LOG.atWarn().withThrowable(fpe).log("Error shifting formula on row {}", box(row.getRowNum()));
             return formula;
         }
     }
diff --git a/src/ooxml/java/org/apache/poi/xssf/usermodel/helpers/XSSFRowShifter.java b/src/ooxml/java/org/apache/poi/xssf/usermodel/helpers/XSSFRowShifter.java
index 4de9c60..ffbc570 100644
--- a/src/ooxml/java/org/apache/poi/xssf/usermodel/helpers/XSSFRowShifter.java
+++ b/src/ooxml/java/org/apache/poi/xssf/usermodel/helpers/XSSFRowShifter.java
@@ -17,11 +17,11 @@
 
 package org.apache.poi.xssf.usermodel.helpers;
 
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.apache.poi.ss.formula.FormulaShifter;
 import org.apache.poi.ss.usermodel.helpers.RowShifter;
 import org.apache.poi.util.Internal;
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
 import org.apache.poi.xssf.usermodel.XSSFRow;
 import org.apache.poi.xssf.usermodel.XSSFSheet;
 
@@ -31,7 +31,7 @@
 // non-Javadoc: When possible, code should be implemented in the RowShifter abstract class to avoid duplication with
 // {@link org.apache.poi.hssf.usermodel.helpers.HSSFRowShifter}
 public final class XSSFRowShifter extends RowShifter {
-    private static final POILogger LOG = POILogFactory.getLogger(XSSFRowShifter.class);
+    private static final Logger LOG = LogManager.getLogger(XSSFRowShifter.class);
 
     public XSSFRowShifter(XSSFSheet sh) {
         super(sh);
diff --git a/src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFDocument.java b/src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFDocument.java
index 64b8770..e454365 100644
--- a/src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFDocument.java
+++ b/src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFDocument.java
@@ -36,6 +36,8 @@
 
 import javax.xml.namespace.QName;
 
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.apache.poi.ooxml.POIXMLDocument;
 import org.apache.poi.ooxml.POIXMLDocumentPart;
 import org.apache.poi.ooxml.POIXMLException;
@@ -55,8 +57,6 @@
 import org.apache.poi.poifs.crypt.HashAlgorithm;
 import org.apache.poi.util.IOUtils;
 import org.apache.poi.util.Internal;
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
 import org.apache.poi.wp.usermodel.HeaderFooterType;
 import org.apache.poi.xddf.usermodel.chart.XDDFChart;
 import org.apache.poi.xwpf.model.XWPFHeaderFooterPolicy;
@@ -81,7 +81,7 @@
  */
 @SuppressWarnings("unused")
 public class XWPFDocument extends POIXMLDocument implements Document, IBody {
-    private static final POILogger LOG = POILogFactory.getLogger(XWPFDocument.class);
+    private static final Logger LOG = LogManager.getLogger(XWPFDocument.class);
 
     protected List<XWPFFooter> footers = new ArrayList<>();
     protected List<XWPFHeader> headers = new ArrayList<>();
@@ -310,7 +310,7 @@
     /**
      * returns an Iterator with paragraphs and tables
      *
-     * @see org.apache.poi.xwpf.usermodel.IBody#getBodyElements()
+     * @see IBody#getBodyElements()
      */
     @Override
     public List<IBodyElement> getBodyElements() {
@@ -322,7 +322,7 @@
     }
 
     /**
-     * @see org.apache.poi.xwpf.usermodel.IBody#getParagraphs()
+     * @see IBody#getParagraphs()
      */
     @Override
     public List<XWPFParagraph> getParagraphs() {
@@ -330,7 +330,7 @@
     }
 
     /**
-     * @see org.apache.poi.xwpf.usermodel.IBody#getTables()
+     * @see IBody#getTables()
      */
     @Override
     public List<XWPFTable> getTables() {
@@ -345,7 +345,7 @@
     }
 
     /**
-     * @see org.apache.poi.xwpf.usermodel.IBody#getTableArray(int)
+     * @see IBody#getTableArray(int)
      */
     @Override
     public XWPFTable getTableArray(int pos) {
@@ -629,9 +629,9 @@
 
     /**
      * Add a new paragraph at position of the cursor. The cursor must be on the
-     * {@link org.apache.xmlbeans.XmlCursor.TokenType#START} tag of an subelement
+     * {@link XmlCursor.TokenType#START} tag of an subelement
      * of the documents body. When this method is done, the cursor passed as
-     * parameter points to the {@link org.apache.xmlbeans.XmlCursor.TokenType#END}
+     * parameter points to the {@link XmlCursor.TokenType#END}
      * of the newly inserted paragraph.
      *
      * @param cursor The cursor-position where the new paragraph should be added.
@@ -1010,7 +1010,7 @@
                     int level = Integer.parseInt(parStyle.substring("Heading".length()));
                     toc.addRow(level, par.getText(), 1, "112723803");
                 } catch (NumberFormatException e) {
-                    LOG.log(POILogger.ERROR, "can't format number in TOC heading", e);
+                    LOG.atError().withThrowable(e).log("can't format number in TOC heading");
                 }
             }
         }
@@ -1542,7 +1542,7 @@
      *
      * @param ctTbl
      * @return a table by its CTTbl-Object or null
-     * @see org.apache.poi.xwpf.usermodel.IBody#getTable(org.openxmlformats.schemas.wordprocessingml.x2006.main.CTTbl)
+     * @see IBody#getTable(CTTbl)
      */
     @Override
     public XWPFTable getTable(CTTbl ctTbl) {
@@ -1565,7 +1565,7 @@
     /**
      * Returns the paragraph that of position pos
      *
-     * @see org.apache.poi.xwpf.usermodel.IBody#getParagraphArray(int)
+     * @see IBody#getParagraphArray(int)
      */
     @Override
     public XWPFParagraph getParagraphArray(int pos) {
@@ -1580,7 +1580,7 @@
      * Actually it is needed of the class XWPFTableCell. Because you have to know to which part the tableCell
      * belongs.
      *
-     * @see org.apache.poi.xwpf.usermodel.IBody#getPart()
+     * @see IBody#getPart()
      */
     @Override
     public POIXMLDocumentPart getPart() {
@@ -1592,7 +1592,7 @@
      * get the PartType of the body, for example
      * DOCUMENT, HEADER, FOOTER, FOOTNOTE,
      *
-     * @see org.apache.poi.xwpf.usermodel.IBody#getPartType()
+     * @see IBody#getPartType()
      */
     @Override
     public BodyType getPartType() {
diff --git a/src/ooxml/testcases/org/apache/poi/openxml4j/opc/TestListParts.java b/src/ooxml/testcases/org/apache/poi/openxml4j/opc/TestListParts.java
index 8e97627..481ce98 100644
--- a/src/ooxml/testcases/org/apache/poi/openxml4j/opc/TestListParts.java
+++ b/src/ooxml/testcases/org/apache/poi/openxml4j/opc/TestListParts.java
@@ -24,15 +24,15 @@
 import java.io.InputStream;
 import java.util.TreeMap;
 
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.apache.poi.openxml4j.OpenXML4JTestDataSamples;
 import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
 
 public final class TestListParts {
-    private static final POILogger LOG = POILogFactory.getLogger(TestListParts.class);
+    private static final Logger LOG = LogManager.getLogger(TestListParts.class);
 
 	private TreeMap<PackagePartName, String> expectedValues;
 
@@ -91,7 +91,7 @@
 
 			for (PackagePart part : p.getParts()) {
 				values.put(part.getPartName(), part.getContentType());
-				LOG.log(POILogger.DEBUG, part.getPartName());
+				LOG.atDebug().log(part.getPartName());
 			}
 
 			// Compare expected values with values return by the package
diff --git a/src/ooxml/testcases/org/apache/poi/openxml4j/opc/TestPackage.java b/src/ooxml/testcases/org/apache/poi/openxml4j/opc/TestPackage.java
index 07e9a17..60e4213 100644
--- a/src/ooxml/testcases/org/apache/poi/openxml4j/opc/TestPackage.java
+++ b/src/ooxml/testcases/org/apache/poi/openxml4j/opc/TestPackage.java
@@ -58,6 +58,8 @@
 import org.apache.commons.compress.archivers.zip.ZipArchiveEntry;
 import org.apache.commons.compress.archivers.zip.ZipArchiveOutputStream;
 import org.apache.commons.compress.archivers.zip.ZipFile;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.apache.poi.EncryptedDocumentException;
 import org.apache.poi.POIDataSamples;
 import org.apache.poi.POITestCase;
@@ -78,8 +80,6 @@
 import org.apache.poi.ss.usermodel.Workbook;
 import org.apache.poi.ss.usermodel.WorkbookFactory;
 import org.apache.poi.util.IOUtils;
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
 import org.apache.poi.util.TempFile;
 import org.apache.poi.xssf.XSSFTestDataSamples;
 import org.apache.poi.xssf.streaming.SXSSFWorkbook;
@@ -98,7 +98,7 @@
 import org.xml.sax.SAXParseException;
 
 public final class TestPackage {
-    private static final POILogger LOG = POILogFactory.getLogger(TestPackage.class);
+    private static final Logger LOG = LogManager.getLogger(TestPackage.class);
 	private static final String NS_OOXML_WP_MAIN = "http://schemas.openxmlformats.org/wordprocessingml/2006/main";
 	private static final String CONTENT_EXT_PROPS = "application/vnd.openxmlformats-officedocument.extended-properties+xml";
 	private static final POIDataSamples xlsSamples = POIDataSamples.getSpreadSheetInstance();
@@ -444,7 +444,7 @@
 
 				for (PackagePart part : p.getParts()) {
 					values.put(part.getPartName(), part.getContentType());
-					LOG.log(POILogger.DEBUG, part.getPartName());
+					LOG.atDebug().log(part.getPartName());
 				}
 
 				// Compare expected values with values return by the package
@@ -478,7 +478,7 @@
 
 				for (PackagePart part : p.getParts()) {
 					values.put(part.getPartName(), part.getContentType());
-					LOG.log(POILogger.DEBUG, part.getPartName());
+					LOG.atDebug().log(part.getPartName());
 				}
 
 				// Compare expected values with values return by the package
diff --git a/src/ooxml/testcases/org/apache/poi/openxml4j/opc/TestRelationships.java b/src/ooxml/testcases/org/apache/poi/openxml4j/opc/TestRelationships.java
index 38c1378..d80c88a 100644
--- a/src/ooxml/testcases/org/apache/poi/openxml4j/opc/TestRelationships.java
+++ b/src/ooxml/testcases/org/apache/poi/openxml4j/opc/TestRelationships.java
@@ -30,9 +30,9 @@
 import java.net.URI;
 import java.util.regex.Pattern;
 
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.apache.poi.openxml4j.OpenXML4JTestDataSamples;
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
 import org.junit.jupiter.api.Test;
 
 
@@ -44,7 +44,7 @@
 	private static final String SHEET_WITH_COMMENTS =
 		"/xl/worksheets/sheet1.xml";
 
-    private static final POILogger LOG = POILogFactory.getLogger(TestPackageCoreProperties.class);
+    private static final Logger LOG = LogManager.getLogger(TestPackageCoreProperties.class);
 
     /**
      * Test relationships are correctly loaded. This at the moment fails (as of r499)
@@ -56,7 +56,7 @@
     void testLoadRelationships() throws Exception {
         InputStream is = openSampleStream("sample.xlsx");
         try (OPCPackage pkg = OPCPackage.open(is)) {
-            LOG.log(POILogger.DEBUG, "1: " + pkg);
+            LOG.atDebug().log("1: {}", pkg);
             PackageRelationshipCollection rels = pkg.getRelationshipsByType(PackageRelationshipTypes.CORE_DOCUMENT);
             PackageRelationship coreDocRelationship = rels.getRelationship(0);
             PackagePart corePart = pkg.getPart(coreDocRelationship);
diff --git a/src/ooxml/testcases/org/apache/poi/poifs/crypt/dsig/TestSignatureInfo.java b/src/ooxml/testcases/org/apache/poi/poifs/crypt/dsig/TestSignatureInfo.java
index f8b7de4..798b559 100644
--- a/src/ooxml/testcases/org/apache/poi/poifs/crypt/dsig/TestSignatureInfo.java
+++ b/src/ooxml/testcases/org/apache/poi/poifs/crypt/dsig/TestSignatureInfo.java
@@ -78,6 +78,8 @@
 import javax.xml.crypto.dsig.dom.DOMSignContext;
 
 import org.apache.jcp.xml.dsig.internal.dom.DOMSignedInfo;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.apache.poi.EncryptedDocumentException;
 import org.apache.poi.POIDataSamples;
 import org.apache.poi.ooxml.POIXMLDocument;
@@ -101,8 +103,6 @@
 import org.apache.poi.ss.usermodel.WorkbookFactory;
 import org.apache.poi.util.IOUtils;
 import org.apache.poi.util.LocaleUtil;
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
 import org.apache.poi.util.TempFile;
 import org.apache.poi.xssf.streaming.SXSSFWorkbook;
 import org.apache.poi.xssf.usermodel.XSSFClientAnchor;
@@ -162,7 +162,7 @@
 import org.w3c.dom.Document;
 
 class TestSignatureInfo {
-    private static final POILogger LOG = POILogFactory.getLogger(TestSignatureInfo.class);
+    private static final Logger LOG = LogManager.getLogger(TestSignatureInfo.class);
     private static final POIDataSamples testdata = POIDataSamples.getXmlDSignInstance();
 
     private static Calendar cal;
@@ -357,7 +357,7 @@
                 assertNotNull(result);
                 assertEquals(1, result.size(), "test-file: " + testFile);
                 X509Certificate signer = result.get(0);
-                LOG.log(POILogger.DEBUG, "signer: ", signer.getSubjectX500Principal());
+                LOG.atDebug().log("signer: {}", signer.getSubjectX500Principal());
 
                 boolean b = si.verifySignature();
                 assertTrue(b, "test-file: " + testFile);
@@ -385,8 +385,8 @@
             assertEquals(2, result.size(), "test-file: " + testFile);
             X509Certificate signer1 = result.get(0);
             X509Certificate signer2 = result.get(1);
-            LOG.log(POILogger.DEBUG, "signer 1: ", signer1.getSubjectX500Principal());
-            LOG.log(POILogger.DEBUG, "signer 2: ", signer2.getSubjectX500Principal());
+            LOG.atDebug().log("signer 1: {}", signer1.getSubjectX500Principal());
+            LOG.atDebug().log("signer 2: {}", signer2.getSubjectX500Principal());
 
             boolean b = si.verifySignature();
             assertTrue(b, "test-file: " + testFile);
@@ -527,8 +527,8 @@
             } else {
                 TimeStampServiceValidator tspValidator = (validateChain, revocationData) -> {
                     for (X509Certificate certificate : validateChain) {
-                        LOG.log(POILogger.DEBUG, "certificate: ", certificate.getSubjectX500Principal());
-                        LOG.log(POILogger.DEBUG, "validity: ", certificate.getNotBefore(), " - ", certificate.getNotAfter());
+                        LOG.atDebug().log("certificate: {}", certificate.getSubjectX500Principal());
+                        LOG.atDebug().log("validity: {} - {}", certificate.getNotBefore(), certificate.getNotAfter());
                     }
                 };
                 signatureConfig.setTspValidator(tspValidator);
diff --git a/src/ooxml/testcases/org/apache/poi/ss/tests/TestWorkbookFactory.java b/src/ooxml/testcases/org/apache/poi/ss/tests/TestWorkbookFactory.java
index 2232d9a..200407e 100644
--- a/src/ooxml/testcases/org/apache/poi/ss/tests/TestWorkbookFactory.java
+++ b/src/ooxml/testcases/org/apache/poi/ss/tests/TestWorkbookFactory.java
@@ -34,6 +34,8 @@
 import java.util.concurrent.Future;
 import java.util.stream.Stream;
 
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.apache.poi.EmptyFileException;
 import org.apache.poi.EncryptedDocumentException;
 import org.apache.poi.POIDataSamples;
@@ -44,9 +46,6 @@
 import org.apache.poi.poifs.filesystem.POIFSFileSystem;
 import org.apache.poi.ss.usermodel.Workbook;
 import org.apache.poi.ss.usermodel.WorkbookFactory;
-import org.apache.poi.util.IOUtils;
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
 import org.apache.poi.util.SuppressForbidden;
 import org.apache.poi.util.TempFile;
 import org.apache.poi.xssf.usermodel.XSSFWorkbook;
@@ -63,7 +62,7 @@
     private static final String[] xlsx_protected = new String[]{"protected_passtika.xlsx", "tika"};
     private static final String txt = "SampleSS.txt";
 
-    private static final POILogger LOGGER = POILogFactory.getLogger(TestWorkbookFactory.class);
+    private static final Logger LOGGER = LogManager.getLogger(TestWorkbookFactory.class);
 
     /**
      * Closes the sample workbook read in from filename.
@@ -95,8 +94,7 @@
                 xwb.close();
             } else {
                 // TODO: close() re-writes the sample-file?! Resort to revert() for now to close file handle...
-                LOGGER.log(POILogger.WARN,
-                    "reverting XSSFWorkbook rather than closing it to avoid close() modifying the file on disk. Refer to bug 58779.");
+                LOGGER.atWarn().log("reverting XSSFWorkbook rather than closing it to avoid close() modifying the file on disk. Refer to bug 58779.");
                 xwb.getPackage().revert();
             }
         } else {
diff --git a/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestFormulaEvaluatorOnXSSF.java b/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestFormulaEvaluatorOnXSSF.java
index 3d820cc..600ce5c 100644
--- a/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestFormulaEvaluatorOnXSSF.java
+++ b/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestFormulaEvaluatorOnXSSF.java
@@ -17,6 +17,7 @@
 
 package org.apache.poi.xssf.usermodel;
 
+import static org.apache.logging.log4j.util.Unbox.box;
 import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.junit.jupiter.api.Assertions.assertNotNull;
 import static org.junit.jupiter.api.Assertions.fail;
@@ -28,6 +29,8 @@
 import java.util.Locale;
 import java.util.stream.Stream;
 
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.apache.poi.hssf.HSSFTestDataSamples;
 import org.apache.poi.openxml4j.opc.OPCPackage;
 import org.apache.poi.openxml4j.opc.PackageAccess;
@@ -40,8 +43,6 @@
 import org.apache.poi.ss.usermodel.Row;
 import org.apache.poi.ss.usermodel.Sheet;
 import org.apache.poi.util.LocaleUtil;
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
 import org.junit.jupiter.api.AfterAll;
 import org.junit.jupiter.params.ParameterizedTest;
 import org.junit.jupiter.params.provider.Arguments;
@@ -58,9 +59,9 @@
  *
  */
 public final class TestFormulaEvaluatorOnXSSF {
-    private static final POILogger LOG = POILogFactory.getLogger(TestFormulaEvaluatorOnXSSF.class);
+    private static final Logger LOG = LogManager.getLogger(TestFormulaEvaluatorOnXSSF.class);
 
-    private static XSSFWorkbook workbook;
+	private static XSSFWorkbook workbook;
     private static Sheet sheet;
     private static FormulaEvaluator evaluator;
     private static Locale userLocale;
@@ -244,12 +245,12 @@
 	 */
 	private static String getTargetFunctionName(Row r) {
 		if(r == null) {
-            LOG.log(POILogger.WARN, "Warning - given null row, can't figure out function name");
+            LOG.atWarn().log("Given null row, can't figure out function name");
 			return null;
 		}
 		Cell cell = r.getCell(SS.COLUMN_INDEX_FUNCTION_NAME);
 		if(cell == null) {
-            LOG.log(POILogger.WARN, "Warning - Row " + r.getRowNum() + " has no cell " + SS.COLUMN_INDEX_FUNCTION_NAME + ", can't figure out function name");
+			LOG.atWarn().log("Row {} has no cell " + SS.COLUMN_INDEX_FUNCTION_NAME + ", can't figure out function name", box(r.getRowNum()));
 			return null;
 		}
 		if(cell.getCellType() == CellType.BLANK) {
diff --git a/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestMatrixFormulasFromXMLSpreadsheet.java b/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestMatrixFormulasFromXMLSpreadsheet.java
index d29fc27..b7f32ac 100644
--- a/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestMatrixFormulasFromXMLSpreadsheet.java
+++ b/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestMatrixFormulasFromXMLSpreadsheet.java
@@ -17,6 +17,7 @@
 
 package org.apache.poi.xssf.usermodel;
 
+import static org.apache.logging.log4j.util.Unbox.box;
 import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.junit.jupiter.api.Assertions.assertNotNull;
 import static org.junit.jupiter.api.Assertions.assertTrue;
@@ -27,6 +28,8 @@
 import java.util.Locale;
 import java.util.stream.Stream;
 
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.apache.poi.ss.formula.eval.ErrorEval;
 import org.apache.poi.ss.formula.functions.BaseTestNumeric;
 import org.apache.poi.ss.usermodel.Cell;
@@ -36,8 +39,6 @@
 import org.apache.poi.ss.usermodel.Row;
 import org.apache.poi.ss.usermodel.Sheet;
 import org.apache.poi.util.LocaleUtil;
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
 import org.apache.poi.xssf.XSSFTestDataSamples;
 import org.junit.jupiter.api.AfterAll;
 import org.junit.jupiter.params.ParameterizedTest;
@@ -46,7 +47,7 @@
 
 public final class TestMatrixFormulasFromXMLSpreadsheet {
 
-    private static final POILogger LOG = POILogFactory.getLogger(TestMatrixFormulasFromXMLSpreadsheet.class);
+    private static final Logger LOG = LogManager.getLogger(TestMatrixFormulasFromXMLSpreadsheet.class);
 
     private static XSSFWorkbook workbook;
     private static Sheet sheet;
@@ -208,13 +209,13 @@
      */
     private static String getTargetFunctionName(Row r) {
         if(r == null) {
-            LOG.log(POILogger.WARN, "Warning - given null row, can't figure out function name");
+            LOG.atWarn().log("Given null row, can't figure out function name");
             return null;
         }
         Cell cell = r.getCell(Navigator.START_OPERATORS_COL_INDEX);
-        LOG.log(POILogger.DEBUG, String.valueOf(Navigator.START_OPERATORS_COL_INDEX));
+        LOG.atDebug().log( box(Navigator.START_OPERATORS_COL_INDEX));
         if(cell == null) {
-            LOG.log(POILogger.WARN, "Warning - Row " + r.getRowNum() + " has no cell " + Navigator.START_OPERATORS_COL_INDEX + ", can't figure out function name");
+            LOG.atWarn().log("Row {} has no cell " + Navigator.START_OPERATORS_COL_INDEX + ", can't figure out function name", box(r.getRowNum()));
             return null;
         }
 
diff --git a/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestMultiSheetFormulaEvaluatorOnXSSF.java b/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestMultiSheetFormulaEvaluatorOnXSSF.java
index 91045bf..4c458ea 100644
--- a/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestMultiSheetFormulaEvaluatorOnXSSF.java
+++ b/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestMultiSheetFormulaEvaluatorOnXSSF.java
@@ -17,6 +17,9 @@
 
 package org.apache.poi.xssf.usermodel;
 
+import static org.apache.logging.log4j.util.Unbox.box;
+import static org.apache.poi.xssf.usermodel.TestMultiSheetFormulaEvaluatorOnXSSF.SS.COLUMN_INDEX_FUNCTION_NAME;
+import static org.apache.poi.xssf.usermodel.TestMultiSheetFormulaEvaluatorOnXSSF.SS.COLUMN_INDEX_TEST_NAME;
 import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.junit.jupiter.api.Assertions.assertNotNull;
 import static org.junit.jupiter.api.Assertions.assertTrue;
@@ -28,6 +31,8 @@
 import java.util.Locale;
 import java.util.stream.Stream;
 
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.apache.poi.hssf.HSSFTestDataSamples;
 import org.apache.poi.openxml4j.opc.OPCPackage;
 import org.apache.poi.openxml4j.opc.PackageAccess;
@@ -38,8 +43,6 @@
 import org.apache.poi.ss.usermodel.FormulaEvaluator;
 import org.apache.poi.ss.usermodel.Row;
 import org.apache.poi.ss.usermodel.Sheet;
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
 import org.junit.jupiter.api.AfterAll;
 import org.junit.jupiter.params.ParameterizedTest;
 import org.junit.jupiter.params.provider.Arguments;
@@ -49,9 +52,9 @@
  * Tests formulas for multi sheet reference (i.e. SUM(Sheet1:Sheet5!A1))
  */
 public final class TestMultiSheetFormulaEvaluatorOnXSSF {
-    private static final POILogger LOG = POILogFactory.getLogger(TestMultiSheetFormulaEvaluatorOnXSSF.class);
+    private static final Logger LOG = LogManager.getLogger(TestMultiSheetFormulaEvaluatorOnXSSF.class);
 
-    private static XSSFWorkbook workbook;
+	private static XSSFWorkbook workbook;
     private static Sheet sheet;
     private static FormulaEvaluator evaluator;
 
@@ -211,12 +214,12 @@
 	 */
 	private static String getTargetFunctionName(Row r) {
 		if(r == null) {
-		    LOG.log(POILogger.WARN, "Warning - given null row, can't figure out function name");
+		    LOG.atWarn().log("Given null row, can't figure out function name");
 			return null;
 		}
-		Cell cell = r.getCell(SS.COLUMN_INDEX_FUNCTION_NAME);
+		Cell cell = r.getCell(COLUMN_INDEX_FUNCTION_NAME);
 		if(cell == null) {
-            LOG.log(POILogger.WARN, "Warning - Row " + r.getRowNum() + " has no cell " + SS.COLUMN_INDEX_FUNCTION_NAME + ", can't figure out function name");
+			LOG.atWarn().log("Row {} has no cell " + COLUMN_INDEX_FUNCTION_NAME + ", can't figure out function name", box(r.getRowNum()));
 			return null;
 		}
 
@@ -232,12 +235,12 @@
 	 */
 	private static String getTargetTestName(Row r) {
 		if(r == null) {
-            LOG.log(POILogger.WARN, "Warning - given null row, can't figure out test name");
+            LOG.atWarn().log("Given null row, can't figure out test name");
 			return null;
 		}
-		Cell cell = r.getCell(SS.COLUMN_INDEX_TEST_NAME);
+		Cell cell = r.getCell(COLUMN_INDEX_TEST_NAME);
 		if(cell == null) {
-		    LOG.log(POILogger.WARN, "Warning - Row " + r.getRowNum() + " has no cell " + SS.COLUMN_INDEX_TEST_NAME + ", can't figure out test name");
+			LOG.atWarn().log("Row {} has no cell " + COLUMN_INDEX_TEST_NAME + ", can't figure out test name", box(r.getRowNum()));
 			return null;
 		}
 		CellType ct = cell.getCellType();
diff --git a/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFBugs.java b/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFBugs.java
index 650754e..562fa9f 100644
--- a/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFBugs.java
+++ b/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFBugs.java
@@ -17,6 +17,9 @@
 
 package org.apache.poi.xssf.usermodel;
 
+import static java.time.Duration.between;
+import static java.time.Instant.now;
+import static org.apache.logging.log4j.util.Unbox.box;
 import static org.apache.poi.extractor.ExtractorFactory.OOXML_PACKAGE;
 import static org.apache.poi.openxml4j.opc.TestContentType.isOldXercesActive;
 import static org.junit.jupiter.api.Assertions.*;
@@ -31,7 +34,6 @@
 import java.io.InputStream;
 import java.io.OutputStream;
 import java.nio.charset.StandardCharsets;
-import java.time.Duration;
 import java.time.Instant;
 import java.util.Arrays;
 import java.util.Calendar;
@@ -45,6 +47,8 @@
 
 import org.apache.commons.compress.archivers.zip.ZipArchiveEntry;
 import org.apache.commons.compress.archivers.zip.ZipFile;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.apache.poi.POIDataSamples;
 import org.apache.poi.common.usermodel.HyperlinkType;
 import org.apache.poi.hssf.HSSFITestDataProvider;
@@ -96,8 +100,6 @@
 import org.apache.poi.ss.util.CellUtil;
 import org.apache.poi.util.LocaleUtil;
 import org.apache.poi.util.NullOutputStream;
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
 import org.apache.poi.util.TempFile;
 import org.apache.poi.util.XMLHelper;
 import org.apache.poi.xssf.SXSSFITestDataProvider;
@@ -117,7 +119,6 @@
 import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTCols;
 import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTDefinedName;
 import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTDefinedNames;
-import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTIgnoredErrors;
 import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTMergeCell;
 import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTMergeCells;
 import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTWorksheet;
@@ -127,7 +128,7 @@
 import org.xml.sax.XMLReader;
 
 public final class TestXSSFBugs extends BaseTestBugzillaIssues {
-    private static final POILogger LOG = POILogFactory.getLogger(TestXSSFBugs.class);
+    private static final Logger LOG = LogManager.getLogger(TestXSSFBugs.class);
 
     public TestXSSFBugs() {
         super(XSSFITestDataProvider.instance);
@@ -2033,7 +2034,6 @@
         "DEC2BIN(A1), org.apache.poi.ss.formula.eval.StringEval [0]"
     })
     void test57196_WorkbookEvaluator(String formula, String expValue) throws IOException {
-        String previousLogger = System.getProperty("org.apache.poi.util.POILogger");
         try (XSSFWorkbook wb = new XSSFWorkbook()) {
             XSSFSheet sheet = wb.createSheet("Sheet1");
             XSSFRow row = sheet.createRow(0);
@@ -2051,13 +2051,6 @@
             ValueEval ve = workbookEvaluator.evaluate(new XSSFEvaluationCell(cell));
 
             assertEquals(expValue, ve.toString());
-        } finally {
-            if (previousLogger == null) {
-                System.clearProperty("org.apache.poi.util.POILogger");
-            } else {
-                System.setProperty("org.apache.poi.util.POILogger", previousLogger);
-            }
-            System.clearProperty("poi.log.level");
         }
     }
 
@@ -3429,24 +3422,24 @@
     void test58896WithFile() throws IOException {
         try (Workbook wb = XSSFTestDataSamples.openSampleWorkbook("58896.xlsx")) {
             Sheet sheet = wb.getSheetAt(0);
-            Instant start = Instant.now();
+            Instant start = now();
 
-            LOG.log(POILogger.INFO, "Autosizing columns...");
+            LOG.atInfo().log("Autosizing columns...");
 
             for (int i = 0; i < 3; ++i) {
-                LOG.log(POILogger.INFO, "Autosize ", i, " - ", Duration.between(start, Instant.now()));
+                LOG.atInfo().log("Autosize {} - {}", box(i), between(start, now()));
                 sheet.autoSizeColumn(i);
             }
 
             for (int i = 0; i < 69 - 35 + 1; ++i)
                 for (int j = 0; j < 8; ++j) {
                     int col = 3 + 2 + i * (8 + 2) + j;
-                    LOG.log(POILogger.INFO, "Autosize ", col, " - ", Duration.between(start, Instant.now()));
+                    LOG.atInfo().log("Autosize {} - {}", box(col), between(start, now()));
                     sheet.autoSizeColumn(col);
                 }
-            LOG.log(POILogger.INFO, Duration.between(start, Instant.now()));
+            LOG.atInfo().log(between(start, now()));
 
-            assertTrue(Duration.between(start, Instant.now()).getSeconds() < 25);
+            assertTrue(between(start, now()).getSeconds() < 25);
         }
     }
 
diff --git a/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFColGrouping.java b/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFColGrouping.java
index a86d722..227dc36 100644
--- a/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFColGrouping.java
+++ b/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFColGrouping.java
@@ -23,8 +23,8 @@
 
 import java.io.IOException;
 
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.apache.poi.xssf.XSSFTestDataSamples;
 import org.junit.jupiter.api.Test;
 import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTCol;
@@ -43,7 +43,7 @@
  */
 class TestXSSFColGrouping {
 
-	private static final POILogger LOG = POILogFactory.getLogger(TestXSSFColGrouping.class);
+	private static final Logger LOG = LogManager.getLogger(TestXSSFColGrouping.class);
 
 
     /**
@@ -65,7 +65,7 @@
                 sheet = wb2.getSheet("test");
 
                 CTCols cols = sheet.getCTWorksheet().getColsArray(0);
-                LOG.log(POILogger.DEBUG, "test52186/cols:" + cols);
+                LOG.atDebug().log("test52186/cols:{}", cols);
                 for (CTCol col : cols.getColArray()) {
                     assertTrue(col.isSetWidth(), "Col width attribute is unset: " + col);
                 }
@@ -91,7 +91,7 @@
             sheet.setColumnGroupCollapsed(4, true);
 
             CTCols cols = sheet.getCTWorksheet().getColsArray(0);
-            LOG.log(POILogger.DEBUG, "test52186_2/cols:" + cols);
+            LOG.atDebug().log("test52186_2/cols:{}", cols);
 
             try (XSSFWorkbook wb2 = XSSFTestDataSamples.writeOutAndReadBack(wb1, "testNoColsWithoutWidthWhenGroupingAndCollapsing")) {
                 sheet = wb2.getSheet("test");
@@ -125,7 +125,7 @@
             sheet.groupColumn((short) 2, (short) 3);
 
             sheet.getCTWorksheet().getColsArray(0);
-            LOG.log(POILogger.DEBUG, "testMergingOverlappingCols_OVERLAPS_2_WRAPS/cols:" + cols);
+            LOG.atDebug().log("testMergingOverlappingCols_OVERLAPS_2_WRAPS/cols:{}", cols);
 
             assertEquals(0, cols.getColArray(0).getOutlineLevel());
             assertEquals(2, cols.getColArray(0).getMin()); // 1 based
@@ -173,7 +173,7 @@
             sheet.groupColumn((short) 1, (short) 5);
 
             cols = sheet.getCTWorksheet().getColsArray(0);
-            LOG.log(POILogger.DEBUG, "testMergingOverlappingCols_OVERLAPS_1_WRAPS/cols:" + cols);
+            LOG.atDebug().log("testMergingOverlappingCols_OVERLAPS_1_WRAPS/cols:{}", cols);
 
             assertEquals(1, cols.getColArray(0).getOutlineLevel());
             assertEquals(2, cols.getColArray(0).getMin()); // 1 based
@@ -221,7 +221,7 @@
             sheet.groupColumn((short) 3, (short) 5);
 
             cols = sheet.getCTWorksheet().getColsArray(0);
-            LOG.log(POILogger.DEBUG, "testMergingOverlappingCols_OVERLAPS_1_MINOR/cols:" + cols);
+            LOG.atDebug().log("testMergingOverlappingCols_OVERLAPS_1_MINOR/cols:{}", cols);
 
             assertEquals(0, cols.getColArray(0).getOutlineLevel());
             assertEquals(3, cols.getColArray(0).getMin()); // 1 based
@@ -270,7 +270,7 @@
             sheet.groupColumn((short) 1, (short) 3);
 
             cols = sheet.getCTWorksheet().getColsArray(0);
-            LOG.log(POILogger.DEBUG, "testMergingOverlappingCols_OVERLAPS_2_MINOR/cols:" + cols);
+            LOG.atDebug().log("testMergingOverlappingCols_OVERLAPS_2_MINOR/cols:{}", cols);
 
             assertEquals(1, cols.getColArray(0).getOutlineLevel());
             assertEquals(2, cols.getColArray(0).getMin()); // 1 based
diff --git a/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFSheetMergeRegions.java b/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFSheetMergeRegions.java
index 983f36c..1cce6eb 100644
--- a/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFSheetMergeRegions.java
+++ b/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFSheetMergeRegions.java
@@ -16,20 +16,21 @@
 ==================================================================== */
 package org.apache.poi.xssf.usermodel;
 
+import static org.apache.logging.log4j.util.Unbox.box;
 import static org.junit.jupiter.api.Assertions.*;
 
 import java.io.IOException;
 import java.util.List;
 
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.apache.poi.ss.util.CellRangeAddress;
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
 import org.apache.poi.xssf.XSSFTestDataSamples;
 import org.junit.jupiter.api.Test;
 
 class TestXSSFSheetMergeRegions {
 
-    private static final POILogger LOG = POILogFactory.getLogger(TestXSSFSheetMergeRegions.class);
+    private static final Logger LOG = LogManager.getLogger(TestXSSFSheetMergeRegions.class);
 
     @Test
     void testMergeRegionsSpeed() throws IOException {
@@ -43,7 +44,7 @@
                 if (millis < 2000) {
                     break;
                 }
-                LOG.log(POILogger.INFO, "Retry ", i, " because run-time is too high: ", millis);
+                LOG.atInfo().log("Retry {} because run-time is too high: {}", box(i),box(millis));
             }
 
             boolean inGump = false;
diff --git a/src/scratchpad/src/org/apache/poi/extractor/ole2/OLE2ScratchpadExtractorFactory.java b/src/scratchpad/src/org/apache/poi/extractor/ole2/OLE2ScratchpadExtractorFactory.java
index 30936c4..70da347 100644
--- a/src/scratchpad/src/org/apache/poi/extractor/ole2/OLE2ScratchpadExtractorFactory.java
+++ b/src/scratchpad/src/org/apache/poi/extractor/ole2/OLE2ScratchpadExtractorFactory.java
@@ -24,6 +24,8 @@
 import java.util.List;
 import java.util.stream.StreamSupport;
 
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.apache.poi.extractor.ExtractorFactory;
 import org.apache.poi.extractor.ExtractorProvider;
 import org.apache.poi.extractor.POIOLE2TextExtractor;
@@ -46,19 +48,17 @@
 import org.apache.poi.poifs.filesystem.POIFSFileSystem;
 import org.apache.poi.sl.extractor.SlideShowExtractor;
 import org.apache.poi.sl.usermodel.SlideShowFactory;
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
 
 /**
  * Scratchpad-specific logic for {@link ExtractorFactory} and
- *  {@link org.apache.poi.extractor.ExtractorFactory}, which permit the other two to run with
+ *  {@link ExtractorFactory}, which permit the other two to run with
  *  no Scratchpad jar (though without functionality!)
  * <p>Note - should not be used standalone, always use via the other
  *  two classes</p>
  */
 @SuppressWarnings("WeakerAccess")
 public class OLE2ScratchpadExtractorFactory implements ExtractorProvider {
-    private static final POILogger LOG = POILogFactory.getLogger(OLE2ScratchpadExtractorFactory.class);
+    private static final Logger LOG = LogManager.getLogger(OLE2ScratchpadExtractorFactory.class);
 
     @Override
     public boolean accepts(FileMagic fm) {
@@ -169,7 +169,7 @@
                     .filter(entry -> entry.getName().startsWith("_"))
                     .forEach(dirs::add);
             } catch(FileNotFoundException e) {
-                LOG.log(POILogger.INFO, "Ignoring FileNotFoundException while extracting Word document", e.getLocalizedMessage());
+                LOG.atInfo().withThrowable(e).log("Ignoring FileNotFoundException while extracting Word document");
                 // ignored here
             }
             //} else if(ext instanceof PowerPointExtractor) {
diff --git a/src/scratchpad/src/org/apache/poi/hdgf/chunks/Chunk.java b/src/scratchpad/src/org/apache/poi/hdgf/chunks/Chunk.java
index ef9d42b..6ccc5a6 100644
--- a/src/scratchpad/src/org/apache/poi/hdgf/chunks/Chunk.java
+++ b/src/scratchpad/src/org/apache/poi/hdgf/chunks/Chunk.java
@@ -19,17 +19,19 @@
 
 import java.util.ArrayList;
 
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.apache.poi.hdgf.chunks.ChunkFactory.CommandDefinition;
 import org.apache.poi.util.LittleEndian;
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
+
+import static org.apache.logging.log4j.util.Unbox.box;
 
 /**
  * Base of all chunks, which hold data, flags etc
  */
 public final class Chunk {
     /** For logging warnings about the structure of the file */
-    private static final POILogger LOG = POILogFactory.getLogger(Chunk.class);
+    private static final Logger LOG = LogManager.getLogger(Chunk.class);
 
     /**
      * The contents of the chunk, excluding the header,
@@ -179,9 +181,7 @@
 
             // Check we seem to have enough data
             if(offset >= contents.length) {
-                LOG.log(POILogger.WARN,
-                        "Command offset ", offset, " past end of data at ", contents.length
-                );
+                LOG.atWarn().log("Command offset {} past end of data at {}", box(offset),box(contents.length));
                 continue;
             }
 
@@ -241,12 +241,11 @@
                     break;
 
                 default:
-                    LOG.log(POILogger.INFO,
-                            "Command of type ", type, " not processed!");
+                    LOG.atInfo().log("Command of type {} not processed!", box(type));
                 }
             }
             catch (Exception e) {
-                LOG.log(POILogger.ERROR, "Unexpected error processing command, ignoring and continuing. Command: ", command, e);
+                LOG.atError().withThrowable(e).log("Unexpected error processing command, ignoring and continuing. Command: {}", command);
             }
 
             // Add to the array
diff --git a/src/scratchpad/src/org/apache/poi/hdgf/chunks/ChunkFactory.java b/src/scratchpad/src/org/apache/poi/hdgf/chunks/ChunkFactory.java
index 6bf22a0..76b5937 100644
--- a/src/scratchpad/src/org/apache/poi/hdgf/chunks/ChunkFactory.java
+++ b/src/scratchpad/src/org/apache/poi/hdgf/chunks/ChunkFactory.java
@@ -26,10 +26,12 @@
 import java.util.Map;
 import java.util.StringTokenizer;
 
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.apache.poi.util.IOUtils;
 import org.apache.poi.util.LocaleUtil;
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
+
+import static org.apache.logging.log4j.util.Unbox.box;
 
 /**
  * Factor class to create the appropriate chunks, which
@@ -59,7 +61,7 @@
 		"/org/apache/poi/hdgf/chunks_parse_cmds.tbl";
 
 	/** For logging problems we spot with the file */
-	private static final POILogger LOG = POILogFactory.getLogger(ChunkFactory.class);
+	private static final Logger LOG = LogManager.getLogger(ChunkFactory.class);
 
 	public ChunkFactory(int version) throws IOException {
 		this.version = version;
@@ -139,8 +141,7 @@
 		// Check we have enough data, and tweak the header size
 		//  as required
 		if(endOfDataPos > data.length) {
-			LOG.log(POILogger.WARN,
-				"Header called for ", header.getLength(), " bytes, but that would take us past the end of the data!");
+			LOG.atWarn().log("Header called for {} bytes, but that would take us past the end of the data!", box(header.getLength()));
 
 			endOfDataPos = data.length;
 			header.setLength(data.length - offset - header.getSizeInBytes());
@@ -165,7 +166,7 @@
 					data, endOfDataPos);
 				endOfDataPos += 8;
 			} else {
-				LOG.log(POILogger.ERROR, "Header claims a length to ", endOfDataPos, " there's then no space for the trailer in the data (", data.length, ")");
+				LOG.atError().log("Header claims a length to {} there's then no space for the trailer in the data ({})", box(endOfDataPos),box(data.length));
 			}
 		}
 		if(header.hasSeparator()) {
@@ -173,7 +174,7 @@
 				separator = new ChunkSeparator(
 						data, endOfDataPos);
 			} else {
-				LOG.log(POILogger.ERROR, "Header claims a length to ", endOfDataPos, " there's then no space for the separator in the data (", data.length, ")");
+				LOG.atError().log("Header claims a length to {} there's then no space for the separator in the data ({})", box(endOfDataPos),box(data.length));
 			}
 		}
 
diff --git a/src/scratchpad/src/org/apache/poi/hdgf/streams/ChunkStream.java b/src/scratchpad/src/org/apache/poi/hdgf/streams/ChunkStream.java
index dc923c5..b977483 100644
--- a/src/scratchpad/src/org/apache/poi/hdgf/streams/ChunkStream.java
+++ b/src/scratchpad/src/org/apache/poi/hdgf/streams/ChunkStream.java
@@ -19,15 +19,17 @@
 
 import java.util.ArrayList;
 
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.apache.poi.hdgf.chunks.Chunk;
 import org.apache.poi.hdgf.chunks.ChunkFactory;
 import org.apache.poi.hdgf.chunks.ChunkHeader;
 import org.apache.poi.hdgf.pointers.Pointer;
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
+
+import static org.apache.logging.log4j.util.Unbox.box;
 
 public final class ChunkStream extends Stream {
-	private static final POILogger LOG = POILogFactory.getLogger(ChunkStream.class);
+	private static final Logger LOG = LogManager.getLogger(ChunkStream.class);
 
 	private final ChunkFactory chunkFactory;
 	/** All the Chunks we contain */
@@ -66,14 +68,14 @@
 
 					pos += chunk.getOnDiskSize();
 				} else {
-					LOG.log(POILogger.WARN, "Needed ", headerSize, " bytes to create the next chunk header, but only found ", (contents.length-pos), " bytes, ignoring rest of data");
+					LOG.atWarn().log("Needed {} bytes to create the next chunk header, but only found {} bytes, ignoring rest of data", box(headerSize),box(contents.length - pos));
 					pos = contents.length;
 				}
 			}
 		}
 		catch (Exception e)
 		{
-			LOG.log(POILogger.ERROR, "Failed to create chunk at ", pos, ", ignoring rest of data." + e);
+			LOG.atError().withThrowable(e).log("Failed to create chunk at {}, ignoring rest of data.", box(pos));
 		}
 
 		chunks = chunksA.toArray(new Chunk[0]);
diff --git a/src/scratchpad/src/org/apache/poi/hemf/record/emf/HemfComment.java b/src/scratchpad/src/org/apache/poi/hemf/record/emf/HemfComment.java
index 0d42389..443a7ee 100644
--- a/src/scratchpad/src/org/apache/poi/hemf/record/emf/HemfComment.java
+++ b/src/scratchpad/src/org/apache/poi/hemf/record/emf/HemfComment.java
@@ -29,6 +29,8 @@
 import java.util.NoSuchElementException;
 import java.util.function.Supplier;
 
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.apache.poi.common.usermodel.GenericRecord;
 import org.apache.poi.hemf.draw.HemfGraphics;
 import org.apache.poi.hemf.draw.HemfGraphics.EmfRenderState;
@@ -43,16 +45,16 @@
 import org.apache.poi.util.LittleEndianConsts;
 import org.apache.poi.util.LittleEndianInputStream;
 import org.apache.poi.util.LocaleUtil;
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
 import org.apache.poi.util.RecordFormatException;
 
+import static org.apache.logging.log4j.util.Unbox.box;
+
 /**
  * Contains arbitrary data
  */
 @Internal
 public class HemfComment {
-    private static final POILogger LOG = POILogFactory.getLogger(HemfComment.class);
+    private static final Logger LOG = LogManager.getLogger(HemfComment.class);
     private static final int MAX_RECORD_LENGTH = HwmfPicture.MAX_RECORD_LENGTH;
 
     public enum HemfCommentRecordType {
@@ -101,7 +103,7 @@
          */
         default void draw(HemfGraphics ctx) {}
 
-        default void calcBounds(Rectangle2D bounds, Rectangle2D viewport, HemfGraphics.EmfRenderState[] renderState) { }
+        default void calcBounds(Rectangle2D bounds, Rectangle2D viewport, EmfRenderState[] renderState) { }
 
 
         @Override
@@ -135,7 +137,7 @@
         }
 
         @Override
-        public void calcBounds(Rectangle2D window, Rectangle2D viewport, HemfGraphics.EmfRenderState[] renderState) {
+        public void calcBounds(Rectangle2D window, Rectangle2D viewport, EmfRenderState[] renderState) {
             data.calcBounds(window, viewport, renderState);
         }
 
@@ -601,8 +603,7 @@
             // some emf comments are truncated, so we don't use readFully here
             int readBytes = leis.read(wmfData);
             if (readBytes < wmfData.length) {
-                LOG.log(POILogger.INFO, "Emf comment with WMF: expected ", wmfData.length,
-                        " bytes - received only ", readBytes, " bytes.");
+                LOG.atInfo().log("Emf comment with WMF: expected {} bytes - received only {} bytes.", box(wmfData.length),box(readBytes));
             }
 
             return leis.getReadIndex()-startIdx;
diff --git a/src/scratchpad/src/org/apache/poi/hmef/attribute/MAPIDateAttribute.java b/src/scratchpad/src/org/apache/poi/hmef/attribute/MAPIDateAttribute.java
index e70d7ca..59d7be5 100644
--- a/src/scratchpad/src/org/apache/poi/hmef/attribute/MAPIDateAttribute.java
+++ b/src/scratchpad/src/org/apache/poi/hmef/attribute/MAPIDateAttribute.java
@@ -23,14 +23,14 @@
 import java.util.Date;
 import java.util.Locale;
 
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.apache.poi.hmef.Attachment;
 import org.apache.poi.hmef.HMEFMessage;
 import org.apache.poi.hpsf.Filetime;
 import org.apache.poi.hsmf.datatypes.MAPIProperty;
 import org.apache.poi.util.LittleEndian;
 import org.apache.poi.util.LocaleUtil;
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
 
 /**
  * A pure-MAPI attribute holding a Date, which applies
@@ -42,7 +42,7 @@
  * @see <a href="https://msdn.microsoft.com/en-us/library/cc433490(v=exchg.80).aspx">[MS-OXPROPS]: Exchange Server Protocols Master Property List</a>
  */
 public final class MAPIDateAttribute extends MAPIAttribute {
-   private static final POILogger LOG = POILogFactory.getLogger(MAPIDateAttribute.class);
+   private static final Logger LOG = LogManager.getLogger(MAPIDateAttribute.class);
    private final Date data;
 
    /**
@@ -80,7 +80,7 @@
          return ((MAPIDateAttribute)attr).getDate();
       }
 
-      LOG.log(POILogger.WARN, "Warning, non date property found: ", attr);
+      LOG.atWarn().log("Warning, non date property found: {}", attr);
       return null;
   }
 }
diff --git a/src/scratchpad/src/org/apache/poi/hmef/attribute/MAPIStringAttribute.java b/src/scratchpad/src/org/apache/poi/hmef/attribute/MAPIStringAttribute.java
index d91449e..9ad7a09 100644
--- a/src/scratchpad/src/org/apache/poi/hmef/attribute/MAPIStringAttribute.java
+++ b/src/scratchpad/src/org/apache/poi/hmef/attribute/MAPIStringAttribute.java
@@ -19,12 +19,12 @@
 
 import java.nio.charset.Charset;
 
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.apache.poi.hmef.Attachment;
 import org.apache.poi.hmef.HMEFMessage;
 import org.apache.poi.hsmf.datatypes.MAPIProperty;
 import org.apache.poi.hsmf.datatypes.Types;
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
 import org.apache.poi.util.StringUtil;
 
 /**
@@ -32,7 +32,7 @@
  *  to a {@link HMEFMessage} or one of its {@link Attachment}s.
  */
 public final class MAPIStringAttribute extends MAPIAttribute {
-   private static final POILogger LOG = POILogFactory.getLogger(MAPIStringAttribute.class);
+   private static final Logger LOG = LogManager.getLogger(MAPIStringAttribute.class);
    private static final String CODEPAGE = "CP1252";
    private final String data;
 
@@ -77,7 +77,7 @@
          return ((MAPIRtfAttribute)attr).getDataString();
       }
 
-      LOG.log(POILogger.WARN, "Warning, non string property found: ", attr);
+      LOG.atWarn().log("Warning, non string property found: {}", attr);
       return null;
   }
 }
diff --git a/src/scratchpad/src/org/apache/poi/hmef/attribute/TNEFDateAttribute.java b/src/scratchpad/src/org/apache/poi/hmef/attribute/TNEFDateAttribute.java
index e9f4e6e..1c64dbe 100644
--- a/src/scratchpad/src/org/apache/poi/hmef/attribute/TNEFDateAttribute.java
+++ b/src/scratchpad/src/org/apache/poi/hmef/attribute/TNEFDateAttribute.java
@@ -26,20 +26,20 @@
 import java.util.Date;
 import java.util.Locale;
 
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.apache.poi.hmef.Attachment;
 import org.apache.poi.hmef.HMEFMessage;
 import org.apache.poi.hpsf.Filetime;
 import org.apache.poi.util.LittleEndian;
 import org.apache.poi.util.LocaleUtil;
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
 
 /**
  * A Date attribute which applies to a {@link HMEFMessage}
  *  or one of its {@link Attachment}s.
  */
 public final class TNEFDateAttribute extends TNEFAttribute {
-   private static final POILogger LOG = POILogFactory.getLogger(TNEFDateAttribute.class);
+   private static final Logger LOG = LogManager.getLogger(TNEFDateAttribute.class);
    private final Date data;
 
    /**
@@ -95,7 +95,7 @@
          return ((TNEFDateAttribute)attr).getDate();
       }
 
-      LOG.log(POILogger.WARN, "Warning, non date property found: ", attr);
+      LOG.atWarn().log("Warning, non date property found: {}", attr);
       return null;
   }
 }
diff --git a/src/scratchpad/src/org/apache/poi/hmef/attribute/TNEFStringAttribute.java b/src/scratchpad/src/org/apache/poi/hmef/attribute/TNEFStringAttribute.java
index e5e79df..d42feaa 100644
--- a/src/scratchpad/src/org/apache/poi/hmef/attribute/TNEFStringAttribute.java
+++ b/src/scratchpad/src/org/apache/poi/hmef/attribute/TNEFStringAttribute.java
@@ -20,10 +20,10 @@
 import java.io.IOException;
 import java.io.InputStream;
 
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.apache.poi.hmef.Attachment;
 import org.apache.poi.hmef.HMEFMessage;
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
 import org.apache.poi.util.StringUtil;
 
 /**
@@ -31,7 +31,7 @@
  *  or one of its {@link Attachment}s.
  */
 public final class TNEFStringAttribute extends TNEFAttribute {
-   private static final POILogger LOG = POILogFactory.getLogger(TNEFStringAttribute.class);
+   private static final Logger LOG = LogManager.getLogger(TNEFStringAttribute.class);
    private final String data;
 
    /**
@@ -78,7 +78,7 @@
          return ((TNEFStringAttribute)attr).getString();
       }
 
-      LOG.log(POILogger.WARN, "Warning, non string property found: ", attr);
+      LOG.atWarn().log("Warning, non string property found: {}", attr);
       return null;
   }
 }
diff --git a/src/scratchpad/src/org/apache/poi/hpbf/model/QuillContents.java b/src/scratchpad/src/org/apache/poi/hpbf/model/QuillContents.java
index 4c50e69..6d5b671 100644
--- a/src/scratchpad/src/org/apache/poi/hpbf/model/QuillContents.java
+++ b/src/scratchpad/src/org/apache/poi/hpbf/model/QuillContents.java
@@ -19,6 +19,8 @@
 
 import java.io.IOException;
 
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.apache.poi.hpbf.model.qcbits.QCBit;
 import org.apache.poi.hpbf.model.qcbits.QCPLCBit;
 import org.apache.poi.hpbf.model.qcbits.QCTextBit;
@@ -27,14 +29,12 @@
 import org.apache.poi.util.IOUtils;
 import org.apache.poi.util.LittleEndian;
 import org.apache.poi.util.LocaleUtil;
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
 
 /**
  * Read Quill Contents (/Quill/QuillSub/CONTENTS) from an HPBF (Publisher .pub) document
  */
 public final class QuillContents extends HPBFPart {
-	private static final POILogger LOG = POILogFactory.getLogger(QuillContents.class);
+	private static final Logger LOG = LogManager.getLogger(QuillContents.class);
 	//arbitrarily selected; may need to increase
 	private static final int MAX_RECORD_LENGTH = 1_000_000;
 
@@ -79,7 +79,7 @@
 						bits[i] = QCPLCBit.createQCPLCBit(thingType, bitType, bitData);
 					} catch (ArrayIndexOutOfBoundsException e) {
 						// bug 60685: fall back so that the rest of the document can be read
-						LOG.log(POILogger.WARN, "Unable to read Quill Contents PLC Bit record. Ignoring this record.");
+						LOG.atWarn().log("Unable to read Quill Contents PLC Bit record. Ignoring this record.");
 						bits[i] = new UnknownQCBit(thingType, bitType, bitData);
 					}
 				} else {
diff --git a/src/scratchpad/src/org/apache/poi/hslf/blip/PICT.java b/src/scratchpad/src/org/apache/poi/hslf/blip/PICT.java
index cc76fef..33dcde3 100644
--- a/src/scratchpad/src/org/apache/poi/hslf/blip/PICT.java
+++ b/src/scratchpad/src/org/apache/poi/hslf/blip/PICT.java
@@ -24,18 +24,20 @@
 import java.io.IOException;
 import java.util.zip.InflaterInputStream;
 
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.apache.poi.hslf.exceptions.HSLFException;
 import org.apache.poi.sl.image.ImageHeaderPICT;
 import org.apache.poi.util.IOUtils;
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
 import org.apache.poi.util.Units;
 
+import static org.apache.logging.log4j.util.Unbox.box;
+
 /**
  * Represents Macintosh PICT picture data.
  */
 public final class PICT extends Metafile {
-    private static final POILogger LOG = POILogFactory.getLogger(PICT.class);
+    private static final Logger LOG = LogManager.getLogger(PICT.class);
 
 
     @Override
@@ -85,7 +87,7 @@
                 out.write(chunk, 0, lastLen);
             }
             // End of picture marker for PICT is 0x00 0xFF
-            LOG.log(POILogger.ERROR, "PICT zip-stream is invalid, read as much as possible. Uncompressed length of header: ", header.getWmfSize(), " / Read bytes: ", out.size(), e);
+            LOG.atError().withThrowable(e).log("PICT zip-stream is invalid, read as much as possible. Uncompressed length of header: {} / Read bytes: {}", box(header.getWmfSize()),box(out.size()));
         }
         return out.toByteArray();
     }
diff --git a/src/scratchpad/src/org/apache/poi/hslf/model/HSLFMetroShape.java b/src/scratchpad/src/org/apache/poi/hslf/model/HSLFMetroShape.java
index f65d0fb..54495aa 100644
--- a/src/scratchpad/src/org/apache/poi/hslf/model/HSLFMetroShape.java
+++ b/src/scratchpad/src/org/apache/poi/hslf/model/HSLFMetroShape.java
@@ -19,6 +19,8 @@
 
 import java.lang.reflect.Method;
 
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.apache.poi.ddf.AbstractEscherOptRecord;
 import org.apache.poi.ddf.EscherComplexProperty;
 import org.apache.poi.ddf.EscherPropertyTypes;
@@ -26,8 +28,6 @@
 import org.apache.poi.hslf.usermodel.HSLFShape;
 import org.apache.poi.sl.usermodel.Shape;
 import org.apache.poi.util.Internal;
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
 
 /**
  * Experimental class for metro blobs, i.e. an alternative escher property
@@ -35,8 +35,8 @@
  */
 @Internal
 public class HSLFMetroShape<T extends Shape<?,?>> {
-    private static final POILogger LOGGER = POILogFactory.getLogger(HSLFMetroShape.class);
-    
+    private static final Logger LOGGER = LogManager.getLogger(HSLFMetroShape.class);
+
     private final HSLFShape shape;
 
     public HSLFMetroShape(HSLFShape shape) {
@@ -81,7 +81,7 @@
             Method m = ms.getMethod("parseShape", byte[].class);
             return (T)m.invoke(null, new Object[]{metroBytes});
         } catch (Exception e) {
-            LOGGER.log(POILogger.ERROR, "can't process metro blob, check if all dependencies for POI OOXML are in the classpath.", e);
+            LOGGER.atError().withThrowable(e).log("can't process metro blob, check if all dependencies for POI OOXML are in the classpath.");
             return null;
         }
     }
diff --git a/src/scratchpad/src/org/apache/poi/hslf/model/textproperties/BitMaskTextProp.java b/src/scratchpad/src/org/apache/poi/hslf/model/textproperties/BitMaskTextProp.java
index 8851d6c..17d5ea5 100644
--- a/src/scratchpad/src/org/apache/poi/hslf/model/textproperties/BitMaskTextProp.java
+++ b/src/scratchpad/src/org/apache/poi/hslf/model/textproperties/BitMaskTextProp.java
@@ -22,9 +22,10 @@
 import java.util.Map;
 import java.util.function.Supplier;
 
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+import org.apache.logging.log4j.message.SimpleMessage;
 import org.apache.poi.util.GenericRecordUtil;
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
 
 /**
  * Definition of a special kind of property of some text, or its
@@ -34,9 +35,9 @@
  *  (but related) properties
  */
 public abstract class BitMaskTextProp extends TextProp {
-    protected static final POILogger LOG = POILogFactory.getLogger(BitMaskTextProp.class);
+    protected static final Logger LOG = LogManager.getLogger(BitMaskTextProp.class);
 
-    private String[] subPropNames;
+	private String[] subPropNames;
 	private int[] subPropMasks;
 	private boolean[] subPropMatches;
 
@@ -148,8 +149,8 @@
 	    setWriteMask(writeMask);
 	    super.setValue(maskValue(val));
 	    if (val != super.getValue()) {
-	        LOG.log(POILogger.WARN, "Style properties of '", getName(), "' don't match mask - output will be sanitized");
-	        if (LOG.check(POILogger.DEBUG)) {
+			LOG.atWarn().log("Style properties of '{}' don't match mask - output will be sanitized", getName());
+			LOG.atDebug().log(() -> {
 	            StringBuilder sb = new StringBuilder("The following style attributes of the '")
 						.append(getName()).append("' property will be ignored:\n");
 	            int i=0;
@@ -159,8 +160,8 @@
 	                }
 	                i++;
 	            }
-	            LOG.log(POILogger.DEBUG, sb.toString());
-	        }
+	            return new SimpleMessage(sb);
+			});
 	    }
 	}
 
diff --git a/src/scratchpad/src/org/apache/poi/hslf/model/textproperties/TextPropCollection.java b/src/scratchpad/src/org/apache/poi/hslf/model/textproperties/TextPropCollection.java
index 2e51499..9155731 100644
--- a/src/scratchpad/src/org/apache/poi/hslf/model/textproperties/TextPropCollection.java
+++ b/src/scratchpad/src/org/apache/poi/hslf/model/textproperties/TextPropCollection.java
@@ -29,13 +29,14 @@
 import java.util.Objects;
 import java.util.function.Supplier;
 
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.apache.poi.common.Duplicatable;
 import org.apache.poi.common.usermodel.GenericRecord;
 import org.apache.poi.hslf.exceptions.HSLFException;
+import org.apache.poi.hslf.record.Record;
 import org.apache.poi.util.HexDump;
 import org.apache.poi.util.LittleEndian;
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
 
 /**
  * For a given run of characters, holds the properties (which could
@@ -44,7 +45,7 @@
  *  properties, and the indent level if required.
  */
 public class TextPropCollection implements GenericRecord, Duplicatable {
-    private static final POILogger LOG = POILogFactory.getLogger(TextPropCollection.class);
+    private static final Logger LOG = LogManager.getLogger(TextPropCollection.class);
 
     /** All the different kinds of paragraph properties we might handle */
     private static final TextProp[] paragraphTextPropTypes = {
@@ -291,12 +292,12 @@
 	    if (!isMasterStyle) {
 	        // First goes the number of characters we affect
 	        // MasterStyles don't have this field
-            org.apache.poi.hslf.record.Record.writeLittleEndian(charactersCovered,o);
+            Record.writeLittleEndian(charactersCovered,o);
 	    }
 
 		// Then we have the indentLevel field if it's a paragraph collection
 		if (textPropType == TextPropType.paragraph && indentLevel > -1) {
-            org.apache.poi.hslf.record.Record.writeLittleEndian(indentLevel, o);
+            Record.writeLittleEndian(indentLevel, o);
 		}
 
 		// Then the mask field
@@ -304,7 +305,7 @@
 		for (TextProp textProp : textProps.values()) {
             mask |= textProp.getWriteMask();
         }
-        org.apache.poi.hslf.record.Record.writeLittleEndian(mask,o);
+        Record.writeLittleEndian(mask,o);
 
 		// Then the contents of all the properties
 		for (TextProp textProp : getTextPropList()) {
@@ -313,9 +314,9 @@
                 // don't add empty properties, as they can't be recognized while reading
                 continue;
             } else if (textProp.getSize() == 2) {
-                org.apache.poi.hslf.record.Record.writeLittleEndian((short)val,o);
+                Record.writeLittleEndian((short)val,o);
             } else if (textProp.getSize() == 4) {
-                org.apache.poi.hslf.record.Record.writeLittleEndian(val,o);
+                Record.writeLittleEndian(val,o);
             } else if (textProp instanceof HSLFTabStopPropCollection) {
                 ((HSLFTabStopPropCollection)textProp).writeProperty(o);
             }
@@ -383,7 +384,7 @@
             byte[] b = baos.toByteArray();
             out.append(HexDump.dump(b, 0, 0));
         } catch (IOException e ) {
-            LOG.log(POILogger.ERROR, "can't dump TextPropCollection", e);
+            LOG.atError().withThrowable(e).log("can't dump TextPropCollection");
         }
 
         return out.toString();
diff --git a/src/scratchpad/src/org/apache/poi/hslf/record/AnimationInfo.java b/src/scratchpad/src/org/apache/poi/hslf/record/AnimationInfo.java
index ded2095..9bf2bf7 100644
--- a/src/scratchpad/src/org/apache/poi/hslf/record/AnimationInfo.java
+++ b/src/scratchpad/src/org/apache/poi/hslf/record/AnimationInfo.java
@@ -22,7 +22,8 @@
 import java.util.Arrays;
 
 import org.apache.poi.util.LittleEndian;
-import org.apache.poi.util.POILogger;
+
+import static org.apache.logging.log4j.util.Unbox.box;
 
 /**
  * A container record that specifies information about animation information for a shape.
@@ -55,10 +56,11 @@
 	private void findInterestingChildren() {
 
 		// First child should be the ExMediaAtom
-		if(_children[0] instanceof AnimationInfoAtom) {
-			animationAtom = (AnimationInfoAtom)_children[0];
+		final Record child = _children[0];
+		if(child instanceof AnimationInfoAtom) {
+			animationAtom = (AnimationInfoAtom) child;
 		} else {
-			LOG.log(POILogger.ERROR, "First child record wasn't a AnimationInfoAtom, was of type ", _children[0].getRecordType());
+			LOG.atError().log("First child record wasn't a AnimationInfoAtom, was of type {}", box(child.getRecordType()));
 		}
 	}
 
diff --git a/src/scratchpad/src/org/apache/poi/hslf/record/Comment2000.java b/src/scratchpad/src/org/apache/poi/hslf/record/Comment2000.java
index 9f12084..69c8d21 100644
--- a/src/scratchpad/src/org/apache/poi/hslf/record/Comment2000.java
+++ b/src/scratchpad/src/org/apache/poi/hslf/record/Comment2000.java
@@ -22,7 +22,8 @@
 import java.util.Arrays;
 
 import org.apache.poi.util.LittleEndian;
-import org.apache.poi.util.POILogger;
+
+import static org.apache.logging.log4j.util.Unbox.box;
 
 /**
  * This class represents a comment on a slide, in the format used by
@@ -129,7 +130,7 @@
             } else if (r instanceof Comment2000Atom){
                 commentAtom = (Comment2000Atom)r;
             } else {
-                LOG.log(POILogger.WARN, "Unexpected record with type=", r.getRecordType(), " in Comment2000: ", r.getClass().getName());
+				LOG.atWarn().log("Unexpected record with type={} in Comment2000: {}", box(r.getRecordType()),r.getClass().getName());
             }
         }
 
diff --git a/src/scratchpad/src/org/apache/poi/hslf/record/CurrentUserAtom.java b/src/scratchpad/src/org/apache/poi/hslf/record/CurrentUserAtom.java
index d3793ce..ebb3fc0 100644
--- a/src/scratchpad/src/org/apache/poi/hslf/record/CurrentUserAtom.java
+++ b/src/scratchpad/src/org/apache/poi/hslf/record/CurrentUserAtom.java
@@ -20,6 +20,7 @@
 
 package org.apache.poi.hslf.record;
 
+import static org.apache.logging.log4j.util.Unbox.box;
 import static org.apache.poi.hslf.usermodel.HSLFSlideShow.PP95_DOCUMENT;
 
 import java.io.ByteArrayInputStream;
@@ -28,6 +29,8 @@
 import java.io.InputStream;
 import java.io.OutputStream;
 
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.apache.poi.hslf.exceptions.CorruptPowerPointFileException;
 import org.apache.poi.hslf.exceptions.OldPowerPointFormatException;
 import org.apache.poi.poifs.filesystem.DirectoryNode;
@@ -35,8 +38,6 @@
 import org.apache.poi.poifs.filesystem.POIFSFileSystem;
 import org.apache.poi.util.IOUtils;
 import org.apache.poi.util.LittleEndian;
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
 import org.apache.poi.util.StringUtil;
 
 /**
@@ -46,7 +47,7 @@
  */
 public class CurrentUserAtom
 {
-	private static final POILogger LOG = POILogFactory.getLogger(CurrentUserAtom.class);
+	private static final Logger LOG = LogManager.getLogger(CurrentUserAtom.class);
 	//arbitrarily selected; may need to increase
 	private static final int MAX_RECORD_LENGTH = 1_000_000;
 
@@ -177,7 +178,7 @@
 		long usernameLen = LittleEndian.getUShort(_contents,20);
 		if(usernameLen > 512) {
 			// Handle the case of it being garbage
-			LOG.log(POILogger.WARN, "Warning - invalid username length ", usernameLen, " found, treating as if there was no username set");
+			LOG.atWarn().log("Invalid username length {} found, treating as if there was no username set", box(usernameLen));
 			usernameLen = 0;
 		}
 
diff --git a/src/scratchpad/src/org/apache/poi/hslf/record/Document.java b/src/scratchpad/src/org/apache/poi/hslf/record/Document.java
index 007c83f..73489a9 100644
--- a/src/scratchpad/src/org/apache/poi/hslf/record/Document.java
+++ b/src/scratchpad/src/org/apache/poi/hslf/record/Document.java
@@ -22,7 +22,7 @@
 import java.util.ArrayList;
 import java.util.Arrays;
 
-import org.apache.poi.util.POILogger;
+import static org.apache.logging.log4j.util.Unbox.box;
 
 /**
  * Master container for Document. There is one of these for every
@@ -161,10 +161,10 @@
 		//  (normally it's 2, or 3 if you have notes)
 		// Complain if it's not
 		if(slwtcount == 0) {
-			LOG.log(POILogger.WARN, "No SlideListWithText's found - there should normally be at least one!");
+			LOG.atWarn().log("No SlideListWithText's found - there should normally be at least one!");
 		}
 		if(slwtcount > 3) {
-			LOG.log(POILogger.WARN, "Found ", slwtcount, " SlideListWithTexts - normally there should only be three!");
+			LOG.atWarn().log("Found {} SlideListWithTexts - normally there should only be three!", box(slwtcount));
 		}
 
 		// Now grab all the SLWTs
diff --git a/src/scratchpad/src/org/apache/poi/hslf/record/ExEmbed.java b/src/scratchpad/src/org/apache/poi/hslf/record/ExEmbed.java
index 7cb1caa..f9443b8 100644
--- a/src/scratchpad/src/org/apache/poi/hslf/record/ExEmbed.java
+++ b/src/scratchpad/src/org/apache/poi/hslf/record/ExEmbed.java
@@ -22,7 +22,8 @@
 import java.util.Arrays;
 
 import org.apache.poi.util.LittleEndian;
-import org.apache.poi.util.POILogger;
+
+import static org.apache.logging.log4j.util.Unbox.box;
 
 /**
  * This data represents an embedded object in the document.
@@ -102,17 +103,19 @@
     private void findInterestingChildren() {
 
         // First child should be the ExHyperlinkAtom
-        if(_children[0] instanceof ExEmbedAtom) {
-            embedAtom = (ExEmbedAtom)_children[0];
+        Record child = _children[0];
+        if(child instanceof ExEmbedAtom) {
+            embedAtom = (ExEmbedAtom) child;
         } else {
-            LOG.log(POILogger.ERROR, "First child record wasn't a ExEmbedAtom, was of type ", _children[0].getRecordType());
+            LOG.atError().log("First child record wasn't a ExEmbedAtom, was of type {}", box(child.getRecordType()));
         }
 
         // Second child should be the ExOleObjAtom
-        if (_children[1] instanceof ExOleObjAtom) {
-            oleObjAtom = (ExOleObjAtom)_children[1];
+        child = _children[1];
+        if (child instanceof ExOleObjAtom) {
+            oleObjAtom = (ExOleObjAtom) child;
         } else {
-            LOG.log(POILogger.ERROR, "Second child record wasn't a ExOleObjAtom, was of type ", _children[1].getRecordType());
+            LOG.atError().log("Second child record wasn't a ExOleObjAtom, was of type {}", box(child.getRecordType()));
         }
 
         for (int i = 2; i < _children.length; i++) {
diff --git a/src/scratchpad/src/org/apache/poi/hslf/record/ExHyperlink.java b/src/scratchpad/src/org/apache/poi/hslf/record/ExHyperlink.java
index eeb260c..945a8df 100644
--- a/src/scratchpad/src/org/apache/poi/hslf/record/ExHyperlink.java
+++ b/src/scratchpad/src/org/apache/poi/hslf/record/ExHyperlink.java
@@ -21,7 +21,8 @@
 import java.util.Arrays;
 
 import org.apache.poi.util.LittleEndian;
-import org.apache.poi.util.POILogger;
+
+import static org.apache.logging.log4j.util.Unbox.box;
 
 /**
  * This class represents the data of a link in the document.
@@ -115,18 +116,20 @@
 	private void findInterestingChildren() {
 
 		// First child should be the ExHyperlinkAtom
-		if(_children[0] instanceof ExHyperlinkAtom) {
-			linkAtom = (ExHyperlinkAtom)_children[0];
+		Record child = _children[0];
+		if(child instanceof ExHyperlinkAtom) {
+			linkAtom = (ExHyperlinkAtom) child;
 		} else {
-			LOG.log(POILogger.ERROR, "First child record wasn't a ExHyperlinkAtom, was of type ", _children[0].getRecordType());
+			LOG.atError().log("First child record wasn't a ExHyperlinkAtom, was of type {}", box(child.getRecordType()));
 		}
 
         for (int i = 1; i < _children.length; i++) {
-            if (_children[i] instanceof CString){
-                if ( linkDetailsA == null) linkDetailsA = (CString)_children[i];
-                else linkDetailsB = (CString)_children[i];
+			child = _children[i];
+			if (child instanceof CString){
+                if ( linkDetailsA == null) linkDetailsA = (CString) child;
+                else linkDetailsB = (CString) child;
             } else {
-                LOG.log(POILogger.ERROR, "Record after ExHyperlinkAtom wasn't a CString, was of type ", _children[1].getRecordType());
+                LOG.atError().log("Record after ExHyperlinkAtom wasn't a CString, was of type {}", box(child.getRecordType()));
             }
 
         }
diff --git a/src/scratchpad/src/org/apache/poi/hslf/record/ExMCIMovie.java b/src/scratchpad/src/org/apache/poi/hslf/record/ExMCIMovie.java
index e1f9375..81654df 100644
--- a/src/scratchpad/src/org/apache/poi/hslf/record/ExMCIMovie.java
+++ b/src/scratchpad/src/org/apache/poi/hslf/record/ExMCIMovie.java
@@ -22,7 +22,8 @@
 import java.util.Arrays;
 
 import org.apache.poi.util.LittleEndian;
-import org.apache.poi.util.POILogger;
+
+import static org.apache.logging.log4j.util.Unbox.box;
 
 /**
  * A container record that specifies information about a movie stored externally.
@@ -69,10 +70,11 @@
     private void findInterestingChildren() {
 
         // First child should be the ExVideoContainer
-        if (_children[0] instanceof ExVideoContainer) {
-            exVideo = (ExVideoContainer) _children[0];
+        final Record child = _children[0];
+        if (child instanceof ExVideoContainer) {
+            exVideo = (ExVideoContainer) child;
         } else {
-            LOG.log(POILogger.ERROR, "First child record wasn't a ExVideoContainer, was of type ", _children[0].getRecordType());
+            LOG.atError().log("First child record wasn't a ExVideoContainer, was of type {}", box(child.getRecordType()));
         }
     }
 
diff --git a/src/scratchpad/src/org/apache/poi/hslf/record/ExVideoContainer.java b/src/scratchpad/src/org/apache/poi/hslf/record/ExVideoContainer.java
index 3787a99..c6935e8 100644
--- a/src/scratchpad/src/org/apache/poi/hslf/record/ExVideoContainer.java
+++ b/src/scratchpad/src/org/apache/poi/hslf/record/ExVideoContainer.java
@@ -22,7 +22,8 @@
 import java.util.Arrays;
 
 import org.apache.poi.util.LittleEndian;
-import org.apache.poi.util.POILogger;
+
+import static org.apache.logging.log4j.util.Unbox.box;
 
 /**
  * A container record that specifies information about external video data.
@@ -57,15 +58,17 @@
 	private void findInterestingChildren() {
 
 		// First child should be the ExMediaAtom
-		if(_children[0] instanceof ExMediaAtom) {
-			mediaAtom = (ExMediaAtom)_children[0];
+		Record child = _children[0];
+		if(child instanceof ExMediaAtom) {
+			mediaAtom = (ExMediaAtom) child;
 		} else {
-			LOG.log(POILogger.ERROR, "First child record wasn't a ExMediaAtom, was of type ", _children[0].getRecordType());
+			LOG.atError().log("First child record wasn't a ExMediaAtom, was of type {}", box(child.getRecordType()));
 		}
-        if(_children[1] instanceof CString) {
-            pathAtom = (CString)_children[1];
+		child = _children[1];
+		if(child instanceof CString) {
+            pathAtom = (CString) child;
         } else {
-            LOG.log(POILogger.ERROR, "Second child record wasn't a CString, was of type ", _children[1].getRecordType());
+            LOG.atError().log("Second child record wasn't a CString, was of type {}", box(child.getRecordType()));
         }
 	}
 
diff --git a/src/scratchpad/src/org/apache/poi/hslf/record/FontCollection.java b/src/scratchpad/src/org/apache/poi/hslf/record/FontCollection.java
index c3e17e8..665824f 100644
--- a/src/scratchpad/src/org/apache/poi/hslf/record/FontCollection.java
+++ b/src/scratchpad/src/org/apache/poi/hslf/record/FontCollection.java
@@ -35,7 +35,6 @@
 import org.apache.poi.hslf.usermodel.HSLFFontInfo;
 import org.apache.poi.hslf.usermodel.HSLFFontInfoPredefined;
 import org.apache.poi.util.IOUtils;
-import org.apache.poi.util.POILogger;
 
 /**
  * {@code FontCollection} ia a container that holds information
@@ -62,7 +61,7 @@
 			    HSLFFontInfo fi = addFont(fontHeader);
 			    fi.addFacet(fed);
 			} else {
-				LOG.log(POILogger.WARN, "Warning: FontCollection child wasn't a FontEntityAtom, was ", r.getClass().getSimpleName());
+				LOG.atWarn().log("FontCollection child wasn't a FontEntityAtom, was {}", r.getClass().getSimpleName());
 			}
 		}
 	}
diff --git a/src/scratchpad/src/org/apache/poi/hslf/record/HeadersFootersContainer.java b/src/scratchpad/src/org/apache/poi/hslf/record/HeadersFootersContainer.java
index ff4eaf4..2c1bd86 100644
--- a/src/scratchpad/src/org/apache/poi/hslf/record/HeadersFootersContainer.java
+++ b/src/scratchpad/src/org/apache/poi/hslf/record/HeadersFootersContainer.java
@@ -22,7 +22,8 @@
 import java.util.Arrays;
 
 import org.apache.poi.util.LittleEndian;
-import org.apache.poi.util.POILogger;
+
+import static org.apache.logging.log4j.util.Unbox.box;
 
 /**
  * A container record that specifies information about the footers on a presentation slide.
@@ -89,11 +90,11 @@
                         csFooter = cs;
                         break;
                     default:
-                        LOG.log(POILogger.WARN, "Unexpected CString.Options in HeadersFootersContainer: ", opts);
+                        LOG.atWarn().log("Unexpected CString.Options in HeadersFootersContainer: {}", box(opts));
                         break;
                 }
             } else {
-                LOG.log(POILogger.WARN, "Unexpected record in HeadersFootersContainer: ", child);
+                LOG.atWarn().log("Unexpected record in HeadersFootersContainer: {}", child);
             }
         }
     }
diff --git a/src/scratchpad/src/org/apache/poi/hslf/record/InteractiveInfo.java b/src/scratchpad/src/org/apache/poi/hslf/record/InteractiveInfo.java
index 53cf463..38b0c6e 100644
--- a/src/scratchpad/src/org/apache/poi/hslf/record/InteractiveInfo.java
+++ b/src/scratchpad/src/org/apache/poi/hslf/record/InteractiveInfo.java
@@ -21,7 +21,6 @@
 import java.util.Arrays;
 
 import org.apache.poi.util.LittleEndian;
-import org.apache.poi.util.POILogger;
 
 /**
  * This class represents the metadata of a link in a slide/notes/etc.
@@ -61,7 +60,7 @@
 	private void findInterestingChildren() {
 		// First child should be the InteractiveInfoAtom
 	    if (_children == null || _children.length == 0 || !(_children[0] instanceof InteractiveInfoAtom)) {
-	        LOG.log(POILogger.WARN, "First child record wasn't a InteractiveInfoAtom - leaving this atom in an invalid state...");
+	        LOG.atWarn().log("First child record wasn't a InteractiveInfoAtom - leaving this atom in an invalid state...");
 	        return;
 	    }
 
diff --git a/src/scratchpad/src/org/apache/poi/hslf/record/MasterTextPropAtom.java b/src/scratchpad/src/org/apache/poi/hslf/record/MasterTextPropAtom.java
index 82cc9e1..1e3cf36 100644
--- a/src/scratchpad/src/org/apache/poi/hslf/record/MasterTextPropAtom.java
+++ b/src/scratchpad/src/org/apache/poi/hslf/record/MasterTextPropAtom.java
@@ -31,7 +31,6 @@
 import org.apache.poi.util.GenericRecordUtil;
 import org.apache.poi.util.IOUtils;
 import org.apache.poi.util.LittleEndian;
-import org.apache.poi.util.POILogger;
 
 /**
  * Specifies the Indent Level for the text
@@ -85,7 +84,7 @@
         try {
             read();
         } catch (Exception e){
-            LOG.log(POILogger.ERROR, "Failed to parse MasterTextPropAtom", e);
+            LOG.atError().withThrowable(e).log("Failed to parse MasterTextPropAtom");
         }
     }
 
diff --git a/src/scratchpad/src/org/apache/poi/hslf/record/PPDrawing.java b/src/scratchpad/src/org/apache/poi/hslf/record/PPDrawing.java
index bb55a91..de65b23 100644
--- a/src/scratchpad/src/org/apache/poi/hslf/record/PPDrawing.java
+++ b/src/scratchpad/src/org/apache/poi/hslf/record/PPDrawing.java
@@ -48,7 +48,8 @@
 import org.apache.poi.util.GenericRecordUtil;
 import org.apache.poi.util.IOUtils;
 import org.apache.poi.util.LittleEndian;
-import org.apache.poi.util.POILogger;
+
+import static org.apache.logging.log4j.util.Unbox.box;
 
 /**
  * These are actually wrappers onto Escher drawings. Make use of
@@ -201,7 +202,7 @@
 		// Wind on
 		int size = r.getRecordSize();
 		if(size < 8) {
-			LOG.log(POILogger.WARN, "Hit short DDF record at ", startPos, " - ", size);
+			LOG.atWarn().log("Hit short DDF record at {} - {}", box(startPos),box(size));
 		}
 
 		/*
@@ -211,7 +212,7 @@
 		 * Sometimes it is not so, see an example in bug #44770. Most likely reason is that one of ddf records calculates wrong size.
 		 */
 		if(size != escherBytes){
-			LOG.log(POILogger.WARN, "Record length=", escherBytes, " but getRecordSize() returned ", r.getRecordSize(), "; record: ", r.getClass());
+			LOG.atWarn().log("Record length={} but getRecordSize() returned {}; record: {}", box(escherBytes),box(r.getRecordSize()),r.getClass());
 			size = escherBytes;
 		}
 		startPos += size;
diff --git a/src/scratchpad/src/org/apache/poi/hslf/record/PersistPtrHolder.java b/src/scratchpad/src/org/apache/poi/hslf/record/PersistPtrHolder.java
index 2b3f5ee..1ee2403 100644
--- a/src/scratchpad/src/org/apache/poi/hslf/record/PersistPtrHolder.java
+++ b/src/scratchpad/src/org/apache/poi/hslf/record/PersistPtrHolder.java
@@ -35,7 +35,6 @@
 import org.apache.poi.util.GenericRecordUtil;
 import org.apache.poi.util.IOUtils;
 import org.apache.poi.util.LittleEndian;
-import org.apache.poi.util.POILogger;
 
 /**
  * General holder for PersistPtrFullBlock and PersistPtrIncrementalBlock
@@ -176,8 +175,9 @@
 
             if (newPos == null) {
                 Integer id = me.getKey();
-                LOG.log(POILogger.WARN, "Couldn't find the new location of the \"slide\" with id " + id + " that used to be at " + oldPos);
-                LOG.log(POILogger.WARN, "Not updating the position of it, you probably won't be able to find it any more (if you ever could!)");
+				LOG.atWarn().log("Couldn't find the new location of the \"slide\" with id {} that used to " +
+						"be at {}. Not updating the position of it, you probably won't be able to find it any more " +
+						"(if you ever could!)", id, oldPos);
             } else {
                 me.setValue(newPos);
             }
diff --git a/src/scratchpad/src/org/apache/poi/hslf/record/Record.java b/src/scratchpad/src/org/apache/poi/hslf/record/Record.java
index dba30ed..2b06b4d 100644
--- a/src/scratchpad/src/org/apache/poi/hslf/record/Record.java
+++ b/src/scratchpad/src/org/apache/poi/hslf/record/Record.java
@@ -23,13 +23,15 @@
 import java.util.Arrays;
 import java.util.List;
 
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.apache.poi.common.usermodel.GenericRecord;
 import org.apache.poi.hslf.exceptions.CorruptPowerPointFileException;
 import org.apache.poi.hslf.exceptions.HSLFException;
 import org.apache.poi.hslf.record.RecordTypes.RecordConstructor;
 import org.apache.poi.util.LittleEndian;
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
+
+import static org.apache.logging.log4j.util.Unbox.box;
 
 /**
  * This abstract class represents a record in the PowerPoint document.
@@ -42,7 +44,7 @@
 public abstract class Record implements GenericRecord
 {
     // For logging
-	protected static final POILogger LOG = POILogFactory.getLogger(Record.class);
+	protected static final Logger LOG = LogManager.getLogger(Record.class);
 
 	/**
 	 * Is this record type an Atom record (only has data),
@@ -79,7 +81,7 @@
 	}
 
 	@Override
-	public List<org.apache.poi.hslf.record.Record> getGenericChildren() {
+	public List<Record> getGenericChildren() {
 		Record[] recs = getChildRecords();
 		return (recs == null) ? null : Arrays.asList(recs);
 	}
@@ -107,7 +109,7 @@
 	 * @param b The byte array to build from
 	 * @param offset The offset to build at
 	 */
-	public static org.apache.poi.hslf.record.Record buildRecordAtOffset(byte[] b, int offset) {
+	public static Record buildRecordAtOffset(byte[] b, int offset) {
 		long type = LittleEndian.getUShort(b,offset+2);
 		long rlen = LittleEndian.getUInt(b,offset+4);
 
@@ -122,7 +124,7 @@
 	 * Default method for finding child records of a container record
 	 */
 	public static Record[] findChildRecords(byte[] b, int start, int len) {
-		List<org.apache.poi.hslf.record.Record> children = new ArrayList<>(5);
+		List<Record> children = new ArrayList<>(5);
 
 		// Jump our little way along, creating records as we go
 		int pos = start;
@@ -149,7 +151,7 @@
 		}
 
 		// Turn the vector into an array, and return
-        return children.toArray(new org.apache.poi.hslf.record.Record[0]);
+        return children.toArray(new Record[0]);
 	}
 
 	/**
@@ -161,7 +163,7 @@
 	 *  (not including the size of the header), this code assumes you're
 	 *  passing in corrected lengths
 	 */
-	public static org.apache.poi.hslf.record.Record createRecordForType(long type, byte[] b, int start, int len) {
+	public static Record createRecordForType(long type, byte[] b, int start, int len) {
 		// We use the RecordTypes class to provide us with the right
 		//  class to use for a given type
 		// A spot of reflection gets us the (byte[],int,int) constructor
@@ -183,7 +185,7 @@
 			// Handle case of a corrupt last record, whose claimed length
 			//  would take us passed the end of the file
 			if(start + len > b.length ) {
-				LOG.log(POILogger.WARN, "Warning: Skipping record of type " + type + " at position " + start + " which claims to be longer than the file! (" + len + " vs " + (b.length-start) + ")");
+				LOG.atWarn().log("Warning: Skipping record of type {} at position {} which claims to be longer than the file! ({} vs {})", type, box(start), box(len), box(b.length - start));
 				return null;
 			}
 
diff --git a/src/scratchpad/src/org/apache/poi/hslf/record/Sound.java b/src/scratchpad/src/org/apache/poi/hslf/record/Sound.java
index 41c97a9..2df455b 100644
--- a/src/scratchpad/src/org/apache/poi/hslf/record/Sound.java
+++ b/src/scratchpad/src/org/apache/poi/hslf/record/Sound.java
@@ -21,7 +21,7 @@
 import java.io.OutputStream;
 import java.util.Arrays;
 
-import org.apache.poi.util.POILogger;
+import static org.apache.logging.log4j.util.Unbox.box;
 
 /**
  * A container holding information about a sound. It contains:
@@ -65,17 +65,19 @@
 
     private void findInterestingChildren() {
         // First child should be the ExHyperlinkAtom
-        if(_children[0] instanceof CString) {
-            _name = (CString)_children[0];
+        Record child = _children[0];
+        if(child instanceof CString) {
+            _name = (CString) child;
         } else {
-            LOG.log(POILogger.ERROR, "First child record wasn't a CString, was of type ", _children[0].getRecordType());
+            LOG.atError().log("First child record wasn't a CString, was of type {}", box(child.getRecordType()));
         }
 
         // Second child should be the ExOleObjAtom
-        if (_children[1] instanceof CString) {
-            _type = (CString)_children[1];
+        child = _children[1];
+        if (child instanceof CString) {
+            _type = (CString) child;
         } else {
-            LOG.log(POILogger.ERROR, "Second child record wasn't a CString, was of type ", _children[1].getRecordType());
+            LOG.atError().log("Second child record wasn't a CString, was of type {}", box(child.getRecordType()));
         }
 
         for (int i = 2; i < _children.length; i++) {
diff --git a/src/scratchpad/src/org/apache/poi/hslf/record/StyleTextPropAtom.java b/src/scratchpad/src/org/apache/poi/hslf/record/StyleTextPropAtom.java
index fe9e11f..de2b28c 100644
--- a/src/scratchpad/src/org/apache/poi/hslf/record/StyleTextPropAtom.java
+++ b/src/scratchpad/src/org/apache/poi/hslf/record/StyleTextPropAtom.java
@@ -33,7 +33,8 @@
 import org.apache.poi.util.HexDump;
 import org.apache.poi.util.IOUtils;
 import org.apache.poi.util.LittleEndian;
-import org.apache.poi.util.POILogger;
+
+import static org.apache.logging.log4j.util.Unbox.box;
 
 /**
  * A StyleTextPropAtom (type 4001). Holds basic character properties
@@ -251,7 +252,7 @@
 
         }
         if (rawContents.length > 0 && textHandled != (size+1)){
-            LOG.log(POILogger.WARN, "Problem reading paragraph style runs: textHandled = ", textHandled, ", text.size+1 = ", (size+1));
+            LOG.atWarn().log("Problem reading paragraph style runs: textHandled = {}, text.size+1 = {}", box(textHandled),box(size + 1));
         }
 
         // Now do the character stylings
@@ -283,7 +284,7 @@
             }
         }
         if (rawContents.length > 0 && textHandled != (size+1)){
-            LOG.log(POILogger.WARN, "Problem reading character style runs: textHandled = ", textHandled, ", text.size+1 = ", (size+1));
+            LOG.atWarn().log("Problem reading character style runs: textHandled = {}, text.size+1 = {}", box(textHandled),box(size + 1));
         }
 
         // Handle anything left over
@@ -296,8 +297,7 @@
 
     private int checkTextLength(int readLength, int handledSoFar, int overallSize) {
         if (readLength + handledSoFar > overallSize + 1) {
-            LOG.log(POILogger.WARN, "Style length of ", readLength, " at ", handledSoFar,
-                    " larger than stated size of ", overallSize, ", truncating");
+            LOG.atWarn().log("Style length of {} at {} larger than stated size of {}, truncating", box(readLength),box(handledSoFar),box(overallSize));
             return overallSize + 1 - handledSoFar;
         }
         return readLength;
diff --git a/src/scratchpad/src/org/apache/poi/hslf/record/TextRulerAtom.java b/src/scratchpad/src/org/apache/poi/hslf/record/TextRulerAtom.java
index 9ca6644..5de317c 100644
--- a/src/scratchpad/src/org/apache/poi/hslf/record/TextRulerAtom.java
+++ b/src/scratchpad/src/org/apache/poi/hslf/record/TextRulerAtom.java
@@ -36,7 +36,6 @@
 import org.apache.poi.util.LittleEndian;
 import org.apache.poi.util.LittleEndianByteArrayInputStream;
 import org.apache.poi.util.LittleEndianOutputStream;
-import org.apache.poi.util.POILogger;
 
 /**
  * Ruler of a text as it differs from the style's ruler settings.
@@ -98,7 +97,7 @@
             // Get the record data.
             read(leis);
         } catch (IOException e){
-            LOG.log(POILogger.ERROR, "Failed to parse TextRulerAtom: ", e.getMessage());
+            LOG.atError().withThrowable(e).log("Failed to parse TextRulerAtom");
         }
     }
 
diff --git a/src/scratchpad/src/org/apache/poi/hslf/record/TxMasterStyleAtom.java b/src/scratchpad/src/org/apache/poi/hslf/record/TxMasterStyleAtom.java
index 40a85fa..a396cd9 100644
--- a/src/scratchpad/src/org/apache/poi/hslf/record/TxMasterStyleAtom.java
+++ b/src/scratchpad/src/org/apache/poi/hslf/record/TxMasterStyleAtom.java
@@ -26,6 +26,8 @@
 import java.util.Map;
 import java.util.function.Supplier;
 
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.apache.poi.hslf.exceptions.HSLFException;
 import org.apache.poi.hslf.model.textproperties.TextPropCollection;
 import org.apache.poi.hslf.model.textproperties.TextPropCollection.TextPropType;
@@ -35,8 +37,6 @@
 import org.apache.poi.util.LittleEndian;
 import org.apache.poi.util.LittleEndianConsts;
 import org.apache.poi.util.LittleEndianOutputStream;
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
 
 /**
  * TxMasterStyleAtom atom (4003).
@@ -53,7 +53,7 @@
  * </p>
  */
 public final class TxMasterStyleAtom extends RecordAtom {
-    private static final POILogger LOG = POILogFactory.getLogger(TxMasterStyleAtom.class);
+    private static final Logger LOG = LogManager.getLogger(TxMasterStyleAtom.class);
     //arbitrarily selected; may need to increase
     private static final int MAX_RECORD_LENGTH = 100_000;
 
@@ -79,7 +79,7 @@
         try {
             init();
         } catch (Exception e){
-            LOG.log(POILogger.WARN, "Exception when reading available styles", e);
+            LOG.atWarn().withThrowable(e).log("Exception when reading available styles");
         }
     }
 
diff --git a/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFAutoShape.java b/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFAutoShape.java
index 88a90cb..c02561d 100644
--- a/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFAutoShape.java
+++ b/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFAutoShape.java
@@ -26,6 +26,8 @@
 import java.awt.geom.Rectangle2D;
 import java.util.Iterator;
 
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.apache.poi.ddf.AbstractEscherOptRecord;
 import org.apache.poi.ddf.EscherArrayProperty;
 import org.apache.poi.ddf.EscherContainerRecord;
@@ -47,8 +49,6 @@
 import org.apache.poi.util.BitField;
 import org.apache.poi.util.BitFieldFactory;
 import org.apache.poi.util.LittleEndian;
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
 
 /**
  * Represents an AutoShape.<p>
@@ -57,7 +57,7 @@
  * See {@link ShapeTypes}
  */
 public class HSLFAutoShape extends HSLFTextShape implements AutoShape<HSLFShape,HSLFTextParagraph> {
-    private static final POILogger LOG = POILogFactory.getLogger(HSLFAutoShape.class);
+    private static final Logger LOG = LogManager.getLogger(HSLFAutoShape.class);
 
     static final byte[] SEGMENTINFO_MOVETO   = new byte[]{0x00, 0x40};
     static final byte[] SEGMENTINFO_LINETO   = new byte[]{0x00, (byte)0xAC};
@@ -218,11 +218,11 @@
 
         //sanity check
         if(verticesProp == null) {
-            LOG.log(POILogger.WARN, "Freeform is missing GEOMETRY__VERTICES ");
+            LOG.atWarn().log("Freeform is missing GEOMETRY__VERTICES ");
             return super.getGeometry();
         }
         if(segmentsProp == null) {
-            LOG.log(POILogger.WARN, "Freeform is missing GEOMETRY__SEGMENTINFO ");
+            LOG.atWarn().log("Freeform is missing GEOMETRY__SEGMENTINFO ");
             return super.getGeometry();
         }
 
@@ -236,7 +236,7 @@
 
         while (segIter.hasNext()) {
             byte[] segElem = segIter.next();
-            HSLFAutoShape.PathInfo pi = getPathInfo(segElem);
+            PathInfo pi = getPathInfo(segElem);
             if (pi == null) {
                 continue;
             }
@@ -368,7 +368,7 @@
     }
 
     private static void handleEscapeInfo(Path pathCT, Path2D path2D, byte[] segElem, Iterator<byte[]> vertIter) {
-        HSLFAutoShape.EscapeInfo ei = getEscapeInfo(segElem);
+        EscapeInfo ei = getEscapeInfo(segElem);
         if (ei == null) {
             return;
         }
@@ -466,26 +466,26 @@
         return new Point2D.Double(xyPoints[0],xyPoints[1]);
     }
 
-    private static HSLFAutoShape.PathInfo getPathInfo(byte[] elem) {
+    private static PathInfo getPathInfo(byte[] elem) {
         int elemUS = LittleEndian.getUShort(elem, 0);
         int pathInfo = PATH_INFO.getValue(elemUS);
-        return HSLFAutoShape.PathInfo.valueOf(pathInfo);
+        return PathInfo.valueOf(pathInfo);
     }
 
-    private static HSLFAutoShape.EscapeInfo getEscapeInfo(byte[] elem) {
+    private static EscapeInfo getEscapeInfo(byte[] elem) {
         int elemUS = LittleEndian.getUShort(elem, 0);
         int escInfo = ESCAPE_INFO.getValue(elemUS);
-        return HSLFAutoShape.EscapeInfo.valueOf(escInfo);
+        return EscapeInfo.valueOf(escInfo);
     }
 
 
     private static AdjustPoint fillPoint(byte[] xyMaster, int[] xyPoints) {
         if (xyMaster == null || xyPoints == null) {
-            LOG.log(POILogger.WARN, "Master bytes or points not set - ignore point");
+            LOG.atWarn().log("Master bytes or points not set - ignore point");
             return null;
         }
         if ((xyMaster.length != 4 && xyMaster.length != 8) || xyPoints.length != 2) {
-            LOG.log(POILogger.WARN, "Invalid number of master bytes for a single point - ignore point");
+            LOG.atWarn().log("Invalid number of master bytes for a single point - ignore point");
             return null;
         }
 
diff --git a/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFFill.java b/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFFill.java
index ce45fdf..7fa9323 100644
--- a/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFFill.java
+++ b/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFFill.java
@@ -24,6 +24,8 @@
 import java.util.Collections;
 import java.util.List;
 
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.apache.poi.ddf.AbstractEscherOptRecord;
 import org.apache.poi.ddf.EscherArrayProperty;
 import org.apache.poi.ddf.EscherBSERecord;
@@ -41,19 +43,20 @@
 import org.apache.poi.sl.usermodel.PaintStyle.GradientPaint;
 import org.apache.poi.sl.usermodel.PaintStyle.GradientPaint.GradientType;
 import org.apache.poi.sl.usermodel.PaintStyle.TexturePaint;
+import org.apache.poi.sl.usermodel.PictureData;
 import org.apache.poi.util.BitField;
 import org.apache.poi.util.BitFieldFactory;
 import org.apache.poi.util.LittleEndian;
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
 import org.apache.poi.util.Units;
 
+import static org.apache.logging.log4j.util.Unbox.box;
+
 /**
  * Represents functionality provided by the 'Fill Effects' dialog in PowerPoint.
  */
 @SuppressWarnings("WeakerAccess")
 public final class HSLFFill {
-    private static final POILogger LOG = POILogFactory.getLogger(HSLFFill.class);
+    private static final Logger LOG = LogManager.getLogger(HSLFFill.class);
 
     /**
      *  Fill with a solid color
@@ -263,7 +266,7 @@
             case FILL_PICTURE:
                 return getTexturePaint();
             default:
-                LOG.log(POILogger.WARN, "unsuported fill type: ", fillType);
+                LOG.atWarn().log("unsupported fill type: {}", box(fillType));
                 return null;
         }
     }
@@ -445,7 +448,7 @@
     EscherBSERecord getEscherBSERecord(int idx){
         HSLFSheet sheet = shape.getSheet();
         if(sheet == null) {
-            LOG.log(POILogger.DEBUG, "Fill has not yet been assigned to a sheet");
+            LOG.atDebug().log("Fill has not yet been assigned to a sheet");
             return null;
         }
         HSLFSlideShow ppt = sheet.getSlideShow();
@@ -453,7 +456,7 @@
         EscherContainerRecord dggContainer = doc.getPPDrawingGroup().getDggContainer();
         EscherContainerRecord bstore = HSLFShape.getEscherChild(dggContainer, EscherContainerRecord.BSTORE_CONTAINER);
         if(bstore == null) {
-            LOG.log(POILogger.DEBUG, "EscherContainerRecord.BSTORE_CONTAINER was not found ");
+            LOG.atDebug().log("EscherContainerRecord.BSTORE_CONTAINER was not found ");
             return null;
         }
         List<EscherRecord> lst = bstore.getChildRecords();
@@ -560,10 +563,10 @@
         EscherContainerRecord dggContainer = doc.getPPDrawingGroup().getDggContainer();
         EscherContainerRecord bstore = HSLFShape.getEscherChild(dggContainer, EscherContainerRecord.BSTORE_CONTAINER);
 
-        java.util.List<EscherRecord> lst = bstore.getChildRecords();
+        List<EscherRecord> lst = bstore.getChildRecords();
         int idx = p.getPropertyValue();
         if (idx == 0){
-            LOG.log(POILogger.WARN, "no reference to picture data found ");
+            LOG.atWarn().log("no reference to picture data found ");
         } else {
             EscherBSERecord bse = (EscherBSERecord)lst.get(idx - 1);
             for (HSLFPictureData pd : pict) {
@@ -579,7 +582,7 @@
     /**
      * Assign picture used to fill the underlying shape.
      *
-     * @param data the picture data added to this ppt by {@link HSLFSlideShow#addPicture(byte[], org.apache.poi.sl.usermodel.PictureData.PictureType)} method.
+     * @param data the picture data added to this ppt by {@link HSLFSlideShow#addPicture(byte[], PictureData.PictureType)} method.
      */
     public void setPictureData(HSLFPictureData data){
         AbstractEscherOptRecord opt = shape.getEscherOptRecord();
diff --git a/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFFreeformShape.java b/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFFreeformShape.java
index f3bf2dd..0a3bcc9 100644
--- a/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFFreeformShape.java
+++ b/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFFreeformShape.java
@@ -25,6 +25,8 @@
 import java.util.ArrayList;
 import java.util.List;
 
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.apache.poi.ddf.AbstractEscherOptRecord;
 import org.apache.poi.ddf.EscherArrayProperty;
 import org.apache.poi.ddf.EscherContainerRecord;
@@ -34,10 +36,10 @@
 import org.apache.poi.sl.usermodel.ShapeContainer;
 import org.apache.poi.sl.usermodel.ShapeType;
 import org.apache.poi.util.LittleEndian;
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
 import org.apache.poi.util.Units;
 
+import static org.apache.logging.log4j.util.Unbox.box;
+
 /**
  * A "Freeform" shape.
  *
@@ -47,7 +49,7 @@
  * </p>
  */
 public final class HSLFFreeformShape extends HSLFAutoShape implements FreeformShape<HSLFShape,HSLFTextParagraph> {
-    private static final POILogger LOG = POILogFactory.getLogger(HSLFFreeformShape.class);
+    private static final Logger LOG = LogManager.getLogger(HSLFFreeformShape.class);
 
 
     enum ShapePath {
@@ -138,7 +140,7 @@
                     break;
                 case PathIterator.SEG_QUADTO:
                     //TODO: figure out how to convert SEG_QUADTO into SEG_CUBICTO
-                    LOG.log(POILogger.WARN, "SEG_QUADTO is not supported");
+                    LOG.atWarn().log("SEG_QUADTO is not supported");
                     break;
                 case PathIterator.SEG_CLOSE:
                     pntInfo.add(pntInfo.get(0));
@@ -150,7 +152,7 @@
                     numPoints++;
                     break;
                 default:
-                    LOG.log(POILogger.WARN, "Ignoring invalid segment type ", type);
+                    LOG.atWarn().log("Ignoring invalid segment type {}", box(type));
                     break;
             }
 
diff --git a/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFGroupShape.java b/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFGroupShape.java
index 66cec7e..cfa09db 100644
--- a/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFGroupShape.java
+++ b/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFGroupShape.java
@@ -22,6 +22,8 @@
 import java.util.Iterator;
 import java.util.List;
 
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.apache.poi.ddf.EscherChildAnchorRecord;
 import org.apache.poi.ddf.EscherClientAnchorRecord;
 import org.apache.poi.ddf.EscherContainerRecord;
@@ -33,8 +35,6 @@
 import org.apache.poi.sl.usermodel.ShapeContainer;
 import org.apache.poi.sl.usermodel.ShapeType;
 import org.apache.poi.util.LittleEndian;
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
 import org.apache.poi.util.Units;
 
 /**
@@ -42,7 +42,7 @@
  */
 public class HSLFGroupShape extends HSLFShape
 implements HSLFShapeContainer, GroupShape<HSLFShape,HSLFTextParagraph> {
-    private static final POILogger LOG = POILogFactory.getLogger(HSLFGroupShape.class);
+    private static final Logger LOG = LogManager.getLogger(HSLFGroupShape.class);
 
     /**
       * Create a new ShapeGroup. This constructor is used when a new shape is created.
@@ -207,7 +207,7 @@
         EscherClientAnchorRecord clientAnchor = getEscherChild(EscherClientAnchorRecord.RECORD_ID);
         int x1,y1,x2,y2;
         if(clientAnchor == null){
-            LOG.log(POILogger.INFO, "EscherClientAnchorRecord was not found for shape group. Searching for EscherChildAnchorRecord.");
+            LOG.atInfo().log("EscherClientAnchorRecord was not found for shape group. Searching for EscherChildAnchorRecord.");
             EscherChildAnchorRecord rec = getEscherChild(EscherChildAnchorRecord.RECORD_ID);
             x1 = rec.getDx1();
             y1 = rec.getDy1();
@@ -230,7 +230,7 @@
 
     /**
      * Return type of the shape.
-     * In most cases shape group type is {@link org.apache.poi.sl.usermodel.ShapeType#NOT_PRIMITIVE}
+     * In most cases shape group type is {@link ShapeType#NOT_PRIMITIVE}
      *
      * @return type of the shape.
      */
@@ -289,7 +289,7 @@
             } else {
                 // Should we do anything special with these non
                 //  Container records?
-                LOG.log(POILogger.ERROR, "Shape contained non container escher record, was ", r.getClass().getName());
+                LOG.atError().log("Shape contained non container escher record, was {}", r.getClass().getName());
             }
         }
 
diff --git a/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFNotes.java b/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFNotes.java
index f580679..9377bfa 100644
--- a/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFNotes.java
+++ b/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFNotes.java
@@ -20,12 +20,12 @@
 import java.util.ArrayList;
 import java.util.List;
 
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.apache.poi.hslf.model.HeadersFooters;
 import org.apache.poi.hslf.record.HeadersFootersContainer;
 import org.apache.poi.sl.usermodel.Notes;
 import org.apache.poi.sl.usermodel.Placeholder;
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
 
 /**
  * This class represents a slide's notes in a PowerPoint Document. It
@@ -36,7 +36,7 @@
  */
 
 public final class HSLFNotes extends HSLFSheet implements Notes<HSLFShape,HSLFTextParagraph> {
-    private static final POILogger LOG = POILogFactory.getLogger(HSLFNotes.class);
+    private static final Logger LOG = LogManager.getLogger(HSLFNotes.class);
 
     private final List<List<HSLFTextParagraph>> _paragraphs = new ArrayList<>();
 
@@ -57,7 +57,7 @@
         }
 
         if (_paragraphs.isEmpty()) {
-            LOG.log(POILogger.WARN, "No text records found for notes sheet");
+            LOG.atWarn().log("No text records found for notes sheet");
         }
     }
 
diff --git a/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFObjectData.java b/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFObjectData.java
index c07323d..60f8641 100644
--- a/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFObjectData.java
+++ b/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFObjectData.java
@@ -25,18 +25,18 @@
 import java.util.Map;
 import java.util.function.Supplier;
 
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.apache.poi.common.usermodel.GenericRecord;
 import org.apache.poi.hslf.record.ExOleObjStg;
 import org.apache.poi.sl.usermodel.ObjectData;
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
 
 /**
  * A class that represents object data embedded in a slide show.
  */
 public class HSLFObjectData implements ObjectData, GenericRecord {
-    private static final POILogger LOG = POILogFactory.getLogger(HSLFObjectData.class);
-    
+    private static final Logger LOG = LogManager.getLogger(HSLFObjectData.class);
+
     /**
      * The record that contains the object data.
      */
diff --git a/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFObjectShape.java b/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFObjectShape.java
index af850ec..344e038 100644
--- a/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFObjectShape.java
+++ b/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFObjectShape.java
@@ -22,6 +22,8 @@
 import java.io.IOException;
 import java.io.OutputStream;
 
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.apache.poi.ddf.EscherContainerRecord;
 import org.apache.poi.ddf.EscherPropertyTypes;
 import org.apache.poi.ddf.EscherSpRecord;
@@ -38,15 +40,13 @@
 import org.apache.poi.sl.usermodel.ObjectMetaData.Application;
 import org.apache.poi.sl.usermodel.ObjectShape;
 import org.apache.poi.sl.usermodel.ShapeContainer;
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
 
 
 /**
  * A shape representing embedded OLE object.
  */
 public final class HSLFObjectShape extends HSLFPictureShape implements ObjectShape<HSLFShape,HSLFTextParagraph> {
-    private static final POILogger LOG = POILogFactory.getLogger(HSLFObjectShape.class);
+    private static final Logger LOG = LogManager.getLogger(HSLFObjectShape.class);
 
     private ExEmbed _exEmbed;
 
@@ -104,7 +104,7 @@
 
         HSLFEscherClientDataRecord cldata = getClientData(true);
         ExObjRefAtom uer = null;
-        for (org.apache.poi.hslf.record.Record r : cldata.getHSLFChildRecords()) {
+        for (Record r : cldata.getHSLFChildRecords()) {
             if (r.getRecordType() == RecordTypes.ExObjRefAtom.typeID) {
                 uer = (ExObjRefAtom)r;
                 break;
@@ -141,7 +141,7 @@
             }
         }
         if (data==null) {
-            LOG.log(POILogger.WARN, "OLE data not found");
+            LOG.atWarn().log("OLE data not found");
         }
 
         return data;
@@ -171,7 +171,7 @@
 
             ExObjList lst = ppt.getDocumentRecord().getExObjList(create);
             if(lst == null){
-                LOG.log(POILogger.WARN, "ExObjList not found");
+                LOG.atWarn().log("ExObjList not found");
                 return null;
             }
 
diff --git a/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFPictureShape.java b/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFPictureShape.java
index 353ff71..49921dc 100644
--- a/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFPictureShape.java
+++ b/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFPictureShape.java
@@ -21,6 +21,8 @@
 import java.awt.geom.Rectangle2D;
 import java.util.List;
 
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.apache.poi.ddf.AbstractEscherOptRecord;
 import org.apache.poi.ddf.EscherBSERecord;
 import org.apache.poi.ddf.EscherComplexProperty;
@@ -34,17 +36,17 @@
 import org.apache.poi.sl.usermodel.PictureShape;
 import org.apache.poi.sl.usermodel.ShapeContainer;
 import org.apache.poi.sl.usermodel.ShapeType;
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
 import org.apache.poi.util.StringUtil;
 import org.apache.poi.util.Units;
 
+import static org.apache.logging.log4j.util.Unbox.box;
+
 
 /**
  * Represents a picture in a PowerPoint document.
  */
 public class HSLFPictureShape extends HSLFSimpleShape implements PictureShape<HSLFShape,HSLFTextParagraph> {
-    private static final POILogger LOG = POILogFactory.getLogger(HSLFPictureShape.class);
+    private static final Logger LOG = LogManager.getLogger(HSLFPictureShape.class);
 
     /**
      * Create a new <code>Picture</code>
@@ -120,14 +122,14 @@
 
         EscherBSERecord bse = getEscherBSERecord();
         if (bse == null){
-            LOG.log(POILogger.ERROR, "no reference to picture data found ");
+            LOG.atError().log("no reference to picture data found ");
         } else {
             for (HSLFPictureData pd : pict) {
                 if (pd.getOffset() ==  bse.getOffset()){
                     return pd;
                 }
             }
-            LOG.log(POILogger.ERROR, "no picture found for our BSE offset ", bse.getOffset());
+            LOG.atError().log("no picture found for our BSE offset {}", box(bse.getOffset()));
         }
         return null;
     }
@@ -139,13 +141,13 @@
         EscherContainerRecord dggContainer = doc.getPPDrawingGroup().getDggContainer();
         EscherContainerRecord bstore = HSLFShape.getEscherChild(dggContainer, EscherContainerRecord.BSTORE_CONTAINER);
         if(bstore == null) {
-            LOG.log(POILogger.DEBUG, "EscherContainerRecord.BSTORE_CONTAINER was not found ");
+            LOG.atDebug().log("EscherContainerRecord.BSTORE_CONTAINER was not found ");
             return null;
         }
         List<EscherRecord> lst = bstore.getChildRecords();
         int idx = getPictureIndex();
         if (idx == 0){
-            LOG.log(POILogger.DEBUG, "picture index was not found, returning ");
+            LOG.atDebug().log("picture index was not found, returning ");
             return null;
         }
         return (EscherBSERecord)lst.get(idx-1);
diff --git a/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFShape.java b/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFShape.java
index 24011cc..8fed381 100644
--- a/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFShape.java
+++ b/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFShape.java
@@ -23,6 +23,8 @@
 import java.util.Iterator;
 import java.util.List;
 
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.apache.poi.ddf.AbstractEscherOptRecord;
 import org.apache.poi.ddf.EscherChildAnchorRecord;
 import org.apache.poi.ddf.EscherClientAnchorRecord;
@@ -48,8 +50,6 @@
 import org.apache.poi.sl.usermodel.Shape;
 import org.apache.poi.sl.usermodel.ShapeContainer;
 import org.apache.poi.sl.usermodel.ShapeType;
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
 import org.apache.poi.util.Removal;
 import org.apache.poi.util.StringUtil;
 import org.apache.poi.util.Units;
@@ -69,7 +69,7 @@
  * <p>
  */
 public abstract class HSLFShape implements Shape<HSLFShape,HSLFTextParagraph> {
-    private static final POILogger LOG = POILogFactory.getLogger(HSLFShape.class);
+    private static final Logger LOG = LogManager.getLogger(HSLFShape.class);
 
     /**
      * Either EscherSpContainer or EscheSpgrContainer record
@@ -168,7 +168,7 @@
             y2 = childRec.getDy2();
         } else {
             if (useChildRec) {
-                LOG.log(POILogger.WARN, "EscherSpRecord.FLAG_CHILD is set but EscherChildAnchorRecord was not found");
+                LOG.atWarn().log("EscherSpRecord.FLAG_CHILD is set but EscherChildAnchorRecord was not found");
             }
             EscherClientAnchorRecord clientRec = getEscherChild(EscherClientAnchorRecord.RECORD_ID);
             x1 = clientRec.getCol1();
@@ -715,7 +715,7 @@
     public <T extends Record> T getClientDataRecord(int recordType) {
 
         List<? extends Record> records = getClientRecords();
-        if (records != null) for (org.apache.poi.hslf.record.Record r : records) {
+        if (records != null) for (Record r : records) {
             if (r.getRecordType() == recordType){
                 return (T)r;
             }
diff --git a/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFShapeFactory.java b/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFShapeFactory.java
index 6789649..b13789f 100644
--- a/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFShapeFactory.java
+++ b/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFShapeFactory.java
@@ -19,6 +19,8 @@
 
 import java.util.List;
 
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.apache.poi.ddf.AbstractEscherOptRecord;
 import org.apache.poi.ddf.EscherClientDataRecord;
 import org.apache.poi.ddf.EscherContainerRecord;
@@ -40,15 +42,13 @@
 import org.apache.poi.hslf.record.RecordTypes;
 import org.apache.poi.sl.usermodel.ShapeContainer;
 import org.apache.poi.sl.usermodel.ShapeType;
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
 
 /**
  * Create a <code>Shape</code> object depending on its type
  */
 public final class HSLFShapeFactory {
     // For logging
-    private static final POILogger LOG = POILogFactory.getLogger(HSLFShapeFactory.class);
+    private static final Logger LOG = LogManager.getLogger(HSLFShapeFactory.class);
 
     /**
      * Create a new shape from the data provided.
@@ -112,7 +112,7 @@
                 if (parent instanceof HSLFTable) {
                     EscherTextboxRecord etr = spContainer.getChildById(EscherTextboxRecord.RECORD_ID);
                     if (etr == null) {
-                        LOG.log(POILogger.WARN, "invalid ppt - add EscherTextboxRecord to cell");
+                        LOG.atWarn().log("invalid ppt - add EscherTextboxRecord to cell");
                         etr = new EscherTextboxRecord();
                         etr.setRecordId(EscherTextboxRecord.RECORD_ID);
                         etr.setOptions((short)15);
@@ -153,14 +153,14 @@
             return new HSLFFreeformShape(spContainer, parent);
         }
 
-        LOG.log(POILogger.INFO, "Creating AutoShape for a NotPrimitive shape");
+        LOG.atInfo().log("Creating AutoShape for a NotPrimitive shape");
         return new HSLFAutoShape(spContainer, parent);
     }
 
     @SuppressWarnings("unchecked")
     protected static <T extends Record> T getClientDataRecord(EscherContainerRecord spContainer, int recordType) {
         HSLFEscherClientDataRecord cldata = spContainer.getChildById(EscherClientDataRecord.RECORD_ID);
-        if (cldata != null) for (org.apache.poi.hslf.record.Record r : cldata.getHSLFChildRecords()) {
+        if (cldata != null) for (Record r : cldata.getHSLFChildRecords()) {
             if (r.getRecordType() == recordType) {
                 return (T)r;
             }
diff --git a/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFSimpleShape.java b/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFSimpleShape.java
index 922bbfc..cc9932a 100644
--- a/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFSimpleShape.java
+++ b/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFSimpleShape.java
@@ -19,6 +19,8 @@
 
 import java.awt.Color;
 
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.apache.poi.ddf.AbstractEscherOptRecord;
 import org.apache.poi.ddf.EscherChildAnchorRecord;
 import org.apache.poi.ddf.EscherClientAnchorRecord;
@@ -49,8 +51,6 @@
 import org.apache.poi.sl.usermodel.StrokeStyle.LineCompound;
 import org.apache.poi.sl.usermodel.StrokeStyle.LineDash;
 import org.apache.poi.util.LittleEndian;
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
 import org.apache.poi.util.Units;
 
 /**
@@ -58,7 +58,7 @@
  *  This is the parent class for all primitive shapes like Line, Rectangle, etc.
  */
 public abstract class HSLFSimpleShape extends HSLFShape implements SimpleShape<HSLFShape,HSLFTextParagraph> {
-    private static final POILogger LOG = POILogFactory.getLogger(HSLFSimpleShape.class);
+    private static final Logger LOG = LogManager.getLogger(HSLFSimpleShape.class);
 
     public static final double DEFAULT_LINE_WIDTH = 0.75;
 
@@ -322,7 +322,7 @@
     @Override
     public Guide getAdjustValue(String name) {
         if (name == null || !name.matches("adj([1-9]|10)?")) {
-            LOG.log(POILogger.INFO, "Adjust value '", name, "' not supported. Using default value.");
+            LOG.atInfo().log("Adjust value '{}' not supported. Using default value.", name);
             return null;
         }
 
@@ -384,7 +384,7 @@
             if (name == null) {
                 name = (st != null) ? st.toString() : "<unknown>";
             }
-            LOG.log(POILogger.WARN, "No preset shape definition for shapeType: "+name);
+            LOG.atWarn().log("No preset shape definition for shapeType: {}", name);
         }
 
         return geom;
diff --git a/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFSlideShow.java b/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFSlideShow.java
index 6052a49..908007b 100644
--- a/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFSlideShow.java
+++ b/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFSlideShow.java
@@ -33,6 +33,8 @@
 import java.util.Map;
 import java.util.function.Supplier;
 
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.apache.poi.POIDocument;
 import org.apache.poi.common.usermodel.GenericRecord;
 import org.apache.poi.common.usermodel.fonts.FontInfo;
@@ -61,10 +63,10 @@
 import org.apache.poi.util.GenericRecordUtil;
 import org.apache.poi.util.IOUtils;
 import org.apache.poi.util.Internal;
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
 import org.apache.poi.util.Units;
 
+import static org.apache.logging.log4j.util.Unbox.box;
+
 /**
  * This class is a friendly wrapper on top of the more scary HSLFSlideShow.
  *
@@ -79,7 +81,7 @@
 	public static final String PP95_DOCUMENT = "PP40";
 
 	// For logging
-	private static final POILogger LOG = POILogFactory.getLogger(HSLFSlideShow.class);
+	private static final Logger LOG = LogManager.getLogger(HSLFSlideShow.class);
 
 	//arbitrarily selected; may need to increase
 	private static final int MAX_RECORD_LENGTH = 10_000_000;
@@ -94,7 +96,7 @@
 
 	// Pointers to the most recent versions of the core records
 	// (Document, Notes, Slide etc)
-	private org.apache.poi.hslf.record.Record[] _mostRecentCoreRecords;
+	private Record[] _mostRecentCoreRecords;
 	// Lookup between the PersitPtr "sheet" IDs, and the position
 	// in the mostRecentCoreRecords array
 	private Map<Integer,Integer> _sheetIdToCoreRecordsLookup;
@@ -125,7 +127,7 @@
 	    _hslfSlideShow = hslfSlideShow;
 
 		// Handle Parent-aware Records
-		for (org.apache.poi.hslf.record.Record record : _hslfSlideShow.getRecords()) {
+		for (Record record : _hslfSlideShow.getRecords()) {
 			if(record instanceof RecordContainer){
                 RecordContainer.handleParentAwareRecords((RecordContainer)record);
             }
@@ -187,7 +189,7 @@
 	private void findMostRecentCoreRecords() {
 		// To start with, find the most recent in the byte offset domain
 		Map<Integer,Integer> mostRecentByBytes = new HashMap<>();
-		for (org.apache.poi.hslf.record.Record record : _hslfSlideShow.getRecords()) {
+		for (Record record : _hslfSlideShow.getRecords()) {
 			if (record instanceof PersistPtrHolder) {
 				PersistPtrHolder pph = (PersistPtrHolder) record;
 
@@ -208,7 +210,7 @@
 
 		// We now know how many unique special records we have, so init
 		// the array
-		_mostRecentCoreRecords = new org.apache.poi.hslf.record.Record[mostRecentByBytes.size()];
+		_mostRecentCoreRecords = new Record[mostRecentByBytes.size()];
 
 		// We'll also want to be able to turn the slide IDs into a position
 		// in this array
@@ -225,7 +227,7 @@
 		}
 
 		// Now convert the byte offsets back into record offsets
-		for (org.apache.poi.hslf.record.Record record : _hslfSlideShow.getRecords()) {
+		for (Record record : _hslfSlideShow.getRecords()) {
 			if (!(record instanceof PositionDependentRecord)) {
                 continue;
             }
@@ -253,7 +255,7 @@
 		}
 
 		// Now look for the interesting records in there
-		for (org.apache.poi.hslf.record.Record record : _mostRecentCoreRecords) {
+		for (Record record : _mostRecentCoreRecords) {
 			// Check there really is a record at this number
 			if (record != null) {
 				// Find the Document, and interesting things in it
@@ -272,7 +274,7 @@
 	 * For a given SlideAtomsSet, return the core record, based on the refID
 	 * from the SlidePersistAtom
 	 */
-	public org.apache.poi.hslf.record.Record getCoreRecordForSAS(SlideAtomsSet sas) {
+	public Record getCoreRecordForSAS(SlideAtomsSet sas) {
 		SlidePersistAtom spa = sas.getSlidePersistAtom();
 		int refID = spa.getRefID();
 		return getCoreRecordForRefID(refID);
@@ -285,13 +287,12 @@
 	 * @param refID
 	 *            the refID
 	 */
-	public org.apache.poi.hslf.record.Record getCoreRecordForRefID(int refID) {
+	public Record getCoreRecordForRefID(int refID) {
 		Integer coreRecordId = _sheetIdToCoreRecordsLookup.get(refID);
 		if (coreRecordId != null) {
 			return _mostRecentCoreRecords[coreRecordId];
 		}
-		LOG.log(POILogger.ERROR,
-				"We tried to look up a reference to a core record, but there was no core ID for reference ID ", refID);
+		LOG.atError().log("We tried to look up a reference to a core record, but there was no core ID for reference ID {}", box(refID));
 		return null;
 	}
 
@@ -349,7 +350,7 @@
         }
 
         for (SlideAtomsSet sas : masterSLWT.getSlideAtomsSets()) {
-            org.apache.poi.hslf.record.Record r = getCoreRecordForSAS(sas);
+            Record r = getCoreRecordForSAS(sas);
             int sheetNo = sas.getSlidePersistAtom().getSlideIdentifier();
             if (r instanceof Slide) {
                 HSLFTitleMaster master = new HSLFTitleMaster((Slide)r, sheetNo);
@@ -375,20 +376,20 @@
         for (SlideAtomsSet notesSet : notesSLWT.getSlideAtomsSets()) {
             idx++;
             // Get the right core record
-            org.apache.poi.hslf.record.Record r = getCoreRecordForSAS(notesSet);
+            Record r = getCoreRecordForSAS(notesSet);
             SlidePersistAtom spa = notesSet.getSlidePersistAtom();
 
             String loggerLoc = "A Notes SlideAtomSet at "+idx+" said its record was at refID "+spa.getRefID();
 
             // we need to add null-records, otherwise the index references to other existing don't work anymore
             if (r == null) {
-                LOG.log(POILogger.WARN, loggerLoc+", but that record didn't exist - record ignored.");
+				LOG.atWarn().log("{}, but that record didn't exist - record ignored.", loggerLoc);
                 continue;
             }
 
             // Ensure it really is a notes record
             if (!(r instanceof Notes)) {
-                LOG.log(POILogger.ERROR, loggerLoc, ", but that was actually a ", r);
+				LOG.atError().log("{}, but that was actually a {}", loggerLoc, r);
                 continue;
             }
 
@@ -416,14 +417,11 @@
             idx++;
             // Get the right core record
             SlidePersistAtom spa = sas.getSlidePersistAtom();
-            org.apache.poi.hslf.record.Record r = getCoreRecordForSAS(sas);
+            Record r = getCoreRecordForSAS(sas);
 
             // Ensure it really is a slide record
             if (!(r instanceof Slide)) {
-                LOG.log(POILogger.ERROR, "A Slide SlideAtomSet at ", idx,
-                        " said its record was at refID ",
-                        spa.getRefID(),
-                        ", but that was actually a ", r);
+				LOG.atError().log("A Slide SlideAtomSet at {} said its record was at refID {}, but that was actually a {}", box(idx),box(spa.getRefID()),r);
                 continue;
             }
 
@@ -439,7 +437,7 @@
                 if (notesPos != null && 0 <= notesPos && notesPos < _notes.size()) {
                     notes = _notes.get(notesPos);
                 } else {
-                    LOG.log(POILogger.ERROR, "Notes not found for noteId=", noteId);
+                    LOG.atError().log("Notes not found for noteId={}", box(noteId));
                 }
             }
 
@@ -499,7 +497,7 @@
 	 * Returns an array of the most recent version of all the interesting
 	 * records
 	 */
-	public org.apache.poi.hslf.record.Record[] getMostRecentCoreRecords() {
+	public Record[] getMostRecentCoreRecords() {
 		return _mostRecentCoreRecords;
 	}
 
@@ -618,13 +616,13 @@
 		_slides.get(newSlideNumber - 1).setSlideNumber(newSlideNumber);
 		_slides.get(oldSlideNumber - 1).setSlideNumber(oldSlideNumber);
 
-		ArrayList<org.apache.poi.hslf.record.Record> lst = new ArrayList<>();
+		ArrayList<Record> lst = new ArrayList<>();
 		for (SlideAtomsSet s : sas) {
 			lst.add(s.getSlidePersistAtom());
 			lst.addAll(Arrays.asList(s.getSlideRecords()));
 		}
 
-		org.apache.poi.hslf.record.Record[] r = lst.toArray(new org.apache.poi.hslf.record.Record[0]);
+		Record[] r = lst.toArray(new Record[0]);
 		slwt.setChildRecord(r);
 	}
 
@@ -653,7 +651,7 @@
 		}
 		SlideAtomsSet[] sas = slwt.getSlideAtomsSets();
 
-		List<org.apache.poi.hslf.record.Record> records = new ArrayList<>();
+		List<Record> records = new ArrayList<>();
 		List<SlideAtomsSet> sa = new ArrayList<>(Arrays.asList(sas));
 
 		HSLFSlide removedSlide = _slides.remove(index);
@@ -673,7 +671,7 @@
 			_documentRecord.removeSlideListWithText(slwt);
 		} else {
 			slwt.setSlideAtomsSets(sa.toArray(new SlideAtomsSet[0]));
-			slwt.setChildRecord(records.toArray(new org.apache.poi.hslf.record.Record[0]));
+			slwt.setChildRecord(records.toArray(new Record[0]));
 		}
 
 		// if the removed slide had notes - remove references to them too
@@ -697,7 +695,7 @@
 
 				if (!na.isEmpty()) {
 					nslwt.setSlideAtomsSets(na.toArray(new SlideAtomsSet[0]));
-					nslwt.setChildRecord(records.toArray(new org.apache.poi.hslf.record.Record[0]));
+					nslwt.setChildRecord(records.toArray(new Record[0]));
 				}
 			}
 			if (na.isEmpty()) {
@@ -759,8 +757,7 @@
 
 		// Add in to the list of Slides
 		_slides.add(slide);
-		LOG.log(POILogger.INFO, "Added slide ", _slides.size(), " with ref ", sp.getRefID(),
-				" and identifier ", sp.getSlideIdentifier());
+		LOG.atInfo().log("Added slide {} with ref {} and identifier {}", box(_slides.size()),box(sp.getRefID()),box(sp.getSlideIdentifier()));
 
 		// Add the core records for this new Slide to the record tree
 		Slide slideRecord = slide.getSlideRecord();
@@ -1049,7 +1046,7 @@
 		ExEmbed exEmbed = new ExEmbed();
         // remove unneccessary infos, so we don't need to specify the type
         // of the ole object multiple times
-        org.apache.poi.hslf.record.Record[] children = exEmbed.getChildRecords();
+        Record[] children = exEmbed.getChildRecords();
         exEmbed.removeChild(children[2]);
         exEmbed.removeChild(children[3]);
         exEmbed.removeChild(children[4]);
@@ -1115,7 +1112,7 @@
 
     private int addPersistentObject(PositionDependentRecord slideRecord) {
     	slideRecord.setLastOnDiskOffset(HSLFSlideShowImpl.UNSET_OFFSET);
-		_hslfSlideShow.appendRootLevelRecord((org.apache.poi.hslf.record.Record)slideRecord);
+		_hslfSlideShow.appendRootLevelRecord((Record)slideRecord);
 
         // For position dependent records, hold where they were and now are
         // As we go along, update, and hand over, to any Position Dependent
@@ -1145,7 +1142,7 @@
 		int slideOffset = slideRecord.getLastOnDiskOffset();
 		slideRecord.setLastOnDiskOffset(slideOffset);
 		ptr.addSlideLookup(psrId, slideOffset);
-		LOG.log(POILogger.INFO, "New slide/object ended up at ", slideOffset);
+		LOG.atInfo().log("New slide/object ended up at {}", box(slideOffset));
 
 		return psrId;
     }
diff --git a/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFSlideShowImpl.java b/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFSlideShowImpl.java
index aa5671e..4295712 100644
--- a/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFSlideShowImpl.java
+++ b/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFSlideShowImpl.java
@@ -17,6 +17,7 @@
 
 package org.apache.poi.hslf.usermodel;
 
+import static org.apache.logging.log4j.util.Unbox.box;
 import static org.apache.poi.hslf.usermodel.HSLFSlideShow.POWERPOINT_DOCUMENT;
 import static org.apache.poi.hslf.usermodel.HSLFSlideShow.PP95_DOCUMENT;
 import static org.apache.poi.hslf.usermodel.HSLFSlideShow.PP97_DOCUMENT;
@@ -36,6 +37,8 @@
 import java.util.NavigableMap;
 import java.util.TreeMap;
 
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.apache.poi.POIDocument;
 import org.apache.poi.hpsf.PropertySet;
 import org.apache.poi.hslf.exceptions.CorruptPowerPointFileException;
@@ -60,15 +63,13 @@
 import org.apache.poi.util.IOUtils;
 import org.apache.poi.util.LittleEndian;
 import org.apache.poi.util.LittleEndianConsts;
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
 
 /**
  * This class contains the main functionality for the Powerpoint file
  * "reader". It is only a very basic class for now
  */
 public final class HSLFSlideShowImpl extends POIDocument implements Closeable {
-    private static final POILogger LOG = POILogFactory.getLogger(HSLFSlideShowImpl.class);
+    private static final Logger LOG = LogManager.getLogger(HSLFSlideShowImpl.class);
 
     static final int UNSET_OFFSET = -1;
 
@@ -82,7 +83,7 @@
     private byte[] _docstream;
 
     // Low level contents
-    private org.apache.poi.hslf.record.Record[] _records;
+    private Record[] _records;
 
     // Raw Pictures contained in the pictures stream
     private List<HSLFPictureData> _pictures;
@@ -246,7 +247,7 @@
         _records = read(_docstream, (int) currentUser.getCurrentEditOffset());
     }
 
-    private org.apache.poi.hslf.record.Record[] read(byte[] docstream, int usrOffset) throws IOException {
+    private Record[] read(byte[] docstream, int usrOffset) throws IOException {
         //sort found records by offset.
         //(it is not necessary but SlideShow.findMostRecentCoreRecords() expects them sorted)
         NavigableMap<Integer, Record> records = new TreeMap<>(); // offset -> record
@@ -256,7 +257,7 @@
 
         for (Map.Entry<Integer, Record> entry : records.entrySet()) {
             Integer offset = entry.getKey();
-            org.apache.poi.hslf.record.Record record = entry.getValue();
+            Record record = entry.getValue();
             Integer persistId = persistIds.get(offset);
             if (record == null) {
                 // all plain records have been already added,
@@ -272,7 +273,7 @@
         }
 
         decryptData.close();
-        return records.values().toArray(new org.apache.poi.hslf.record.Record[0]);
+        return records.values().toArray(new Record[0]);
     }
 
     private void initRecordOffsets(byte[] docstream, int usrOffset, NavigableMap<Integer, Record> recordMap, Map<Integer, Integer> offset2id) {
@@ -303,7 +304,7 @@
                 int type = LittleEndian.getUShort(docstream, usrOffset + 2);
                 int len = LittleEndian.getInt(docstream, usrOffset + 4);
                 if (ver_inst == 0 && type == 4085 && (len == 0x1C || len == 0x20)) {
-                    LOG.log(POILogger.WARN, "Repairing invalid user edit atom");
+                    LOG.atWarn().log("Repairing invalid user edit atom");
                     usr.setLastUserEditAtomOffset(usrOffset);
                 } else {
                     throw new CorruptPowerPointFileException("Powerpoint document contains invalid user edit atom");
@@ -313,7 +314,7 @@
     }
 
     public DocumentEncryptionAtom getDocumentEncryptionAtom() {
-        for (org.apache.poi.hslf.record.Record r : _records) {
+        for (Record r : _records) {
             if (r instanceof DocumentEncryptionAtom) {
                 return (DocumentEncryptionAtom) r;
             }
@@ -329,7 +330,7 @@
         try {
             currentUser = new CurrentUserAtom(getDirectory());
         } catch (IOException ie) {
-            LOG.log(POILogger.ERROR, "Error finding Current User Atom", ie);
+            LOG.atError().withThrowable(ie).log("Error finding Current User Atom");
             currentUser = new CurrentUserAtom();
         }
     }
@@ -393,14 +394,13 @@
                 // If they type (including the bonus 0xF018) is 0, skip it
                 PictureType pt = PictureType.forNativeID(type - 0xF018);
                 if (pt == null) {
-                    LOG.log(POILogger.ERROR, "Problem reading picture: Invalid image type 0, on picture with length ", imgsize, ".\nYour document will probably become corrupted if you save it!");
-                    LOG.log(POILogger.ERROR, "position: ", pos);
+                    LOG.atError().log("Problem reading picture: Invalid image type 0, on picture with length {}.\nYour document will probably become corrupted if you save it! Position: {}", box(imgsize),box(pos));
                 } else {
                     //The pictstream can be truncated halfway through a picture.
                     //This is not a problem if the pictstream contains extra pictures
                     //that are not used in any slide -- BUG-60305
                     if (pos + imgsize > pictstream.length) {
-                        LOG.log(POILogger.WARN, "\"Pictures\" stream may have ended early. In some circumstances, this is not a problem; " +
+                        LOG.atWarn().log("\"Pictures\" stream may have ended early. In some circumstances, this is not a problem; " +
                                 "in others, this could indicate a corrupt file");
                         break;
                     }
@@ -417,7 +417,7 @@
                         pict.setIndex(_pictures.size() + 1);        // index is 1-based
                         _pictures.add(pict);
                     } catch (IllegalArgumentException e) {
-                        LOG.log(POILogger.ERROR, "Problem reading picture: ", e, "\nYour document will probably become corrupted if you save it!");
+                        LOG.atError().withThrowable(e).log("Problem reading picture. Your document will probably become corrupted if you save it!");
                     }
                 }
 
@@ -464,7 +464,7 @@
         UserEditAtom usr = null;
         PersistPtrHolder ptr = null;
         CountingOS cos = new CountingOS();
-        for (org.apache.poi.hslf.record.Record record : _records) {
+        for (Record record : _records) {
             // all top level records are position dependent
             assert (record instanceof PositionDependentRecord);
             PositionDependentRecord pdr = (PositionDependentRecord) record;
@@ -506,7 +506,7 @@
         }
 
         try (HSLFSlideShowEncrypted encData = new HSLFSlideShowEncrypted(getDocumentEncryptionAtom())) {
-            for (org.apache.poi.hslf.record.Record record : _records) {
+            for (Record record : _records) {
                 assert (record instanceof PositionDependentRecord);
                 // We've already figured out their new location, and
                 // told them that
@@ -718,7 +718,7 @@
     @SuppressWarnings({"UnusedReturnValue", "WeakerAccess"})
     public synchronized int appendRootLevelRecord(Record newRecord) {
         int addedAt = -1;
-        org.apache.poi.hslf.record.Record[] r = new org.apache.poi.hslf.record.Record[_records.length + 1];
+        Record[] r = new Record[_records.length + 1];
         boolean added = false;
         for (int i = (_records.length - 1); i >= 0; i--) {
             if (added) {
@@ -770,7 +770,7 @@
     /**
      * Returns an array of all the records found in the slideshow
      */
-    public org.apache.poi.hslf.record.Record[] getRecords() {
+    public Record[] getRecords() {
         return _records;
     }
 
@@ -815,7 +815,7 @@
     public HSLFObjectData[] getEmbeddedObjects() {
         if (_objects == null) {
             List<HSLFObjectData> objects = new ArrayList<>();
-            for (org.apache.poi.hslf.record.Record r : _records) {
+            for (Record r : _records) {
                 if (r instanceof ExOleObjStg) {
                     objects.add(new HSLFObjectData((ExOleObjStg) r));
                 }
diff --git a/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFTextParagraph.java b/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFTextParagraph.java
index 867f573..3f1e48c 100644
--- a/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFTextParagraph.java
+++ b/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFTextParagraph.java
@@ -17,6 +17,7 @@
 
 package org.apache.poi.hslf.usermodel;
 
+import static org.apache.logging.log4j.util.Unbox.box;
 import static org.apache.poi.hslf.record.RecordTypes.OutlineTextRefAtom;
 
 import java.awt.Color;
@@ -28,6 +29,8 @@
 import java.util.function.Consumer;
 import java.util.stream.Collectors;
 
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.apache.poi.common.usermodel.fonts.FontGroup;
 import org.apache.poi.common.usermodel.fonts.FontInfo;
 import org.apache.poi.hslf.exceptions.HSLFException;
@@ -48,6 +51,7 @@
 import org.apache.poi.hslf.record.MasterTextPropAtom;
 import org.apache.poi.hslf.record.OutlineTextRefAtom;
 import org.apache.poi.hslf.record.PPDrawing;
+import org.apache.poi.hslf.record.Record;
 import org.apache.poi.hslf.record.RecordContainer;
 import org.apache.poi.hslf.record.RecordTypes;
 import org.apache.poi.hslf.record.RoundTripHFPlaceholder12;
@@ -70,8 +74,6 @@
 import org.apache.poi.sl.usermodel.TabStop.TabStopType;
 import org.apache.poi.sl.usermodel.TextParagraph;
 import org.apache.poi.sl.usermodel.TextShape.TextPlaceholder;
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
 import org.apache.poi.util.StringUtil;
 import org.apache.poi.util.Units;
 
@@ -82,7 +84,7 @@
  */
 
 public final class HSLFTextParagraph implements TextParagraph<HSLFShape,HSLFTextParagraph,HSLFTextRun> {
-    private static final POILogger LOG = POILogFactory.getLogger(HSLFTextParagraph.class);
+    private static final Logger LOG = LogManager.getLogger(HSLFTextParagraph.class);
 
     /**
      * How to align the text
@@ -258,7 +260,7 @@
     /**
      * Returns the type of the text, from the TextHeaderAtom.
      * Possible values can be seen from TextHeaderAtom
-     * @see org.apache.poi.hslf.record.TextHeaderAtom
+     * @see TextHeaderAtom
      */
     public int getRunType() {
         return (_headerAtom != null) ? _headerAtom.getTextType() : -1;
@@ -286,7 +288,7 @@
         _ruler = getTextRuler();
         if (_ruler == null) {
             _ruler = TextRulerAtom.getParagraphInstance();
-            org.apache.poi.hslf.record.Record childAfter = _byteAtom;
+            Record childAfter = _byteAtom;
             if (childAfter == null) {
                 childAfter = _charAtom;
             }
@@ -304,37 +306,37 @@
      *
      * @return text run records
      */
-    public org.apache.poi.hslf.record.Record[] getRecords() {
-        org.apache.poi.hslf.record.Record[] r = _headerAtom.getParentRecord().getChildRecords();
+    public Record[] getRecords() {
+        Record[] r = _headerAtom.getParentRecord().getChildRecords();
         return getRecords(r, new int[] { 0 }, _headerAtom);
     }
 
-    private static org.apache.poi.hslf.record.Record[] getRecords(org.apache.poi.hslf.record.Record[] records, int[] startIdx, TextHeaderAtom headerAtom) {
+    private static Record[] getRecords(Record[] records, int[] startIdx, TextHeaderAtom headerAtom) {
         if (records == null) {
             throw new NullPointerException("records need to be set.");
         }
 
         for (; startIdx[0] < records.length; startIdx[0]++) {
-            org.apache.poi.hslf.record.Record r = records[startIdx[0]];
+            Record r = records[startIdx[0]];
             if (r instanceof TextHeaderAtom && (headerAtom == null || r == headerAtom)) {
                 break;
             }
         }
 
         if (startIdx[0] >= records.length) {
-            LOG.log(POILogger.INFO, "header atom wasn't found - container might contain only an OutlineTextRefAtom");
-            return new org.apache.poi.hslf.record.Record[0];
+            LOG.atInfo().log("header atom wasn't found - container might contain only an OutlineTextRefAtom");
+            return new Record[0];
         }
 
         int length;
         for (length = 1; startIdx[0] + length < records.length; length++) {
-            org.apache.poi.hslf.record.Record r = records[startIdx[0]+length];
+            Record r = records[startIdx[0]+length];
             if (r instanceof TextHeaderAtom || r instanceof SlidePersistAtom) {
                 break;
             }
         }
 
-        org.apache.poi.hslf.record.Record[] result = Arrays.copyOfRange(records, startIdx[0], startIdx[0]+length, org.apache.poi.hslf.record.Record[].class);
+        Record[] result = Arrays.copyOfRange(records, startIdx[0], startIdx[0]+length, Record[].class);
         startIdx[0] += length;
 
         return result;
@@ -884,7 +886,7 @@
         } else {
             master = sheet.getMasterSheet();
             if (master == null) {
-                LOG.log(POILogger.WARN, "MasterSheet is not available");
+                LOG.atWarn().log("MasterSheet is not available");
                 return null;
             }
         }
@@ -970,7 +972,7 @@
     private static StyleTextPropAtom findStyleAtomPresent(TextHeaderAtom header, int textLen) {
         boolean afterHeader = false;
         StyleTextPropAtom style = null;
-        for (org.apache.poi.hslf.record.Record record : header.getParentRecord().getChildRecords()) {
+        for (Record record : header.getParentRecord().getChildRecords()) {
             long rt = record.getRecordType();
             if (afterHeader && rt == RecordTypes.TextHeaderAtom.typeID) {
                 // already on the next header, quit searching
@@ -984,7 +986,7 @@
         }
 
         if (style == null) {
-            LOG.log(POILogger.INFO, "styles atom doesn't exist. Creating dummy record for later saving.");
+            LOG.atInfo().log("styles atom doesn't exist. Creating dummy record for later saving.");
             style = new StyleTextPropAtom((textLen < 0) ? 1 : textLen);
         } else {
             if (textLen >= 0) {
@@ -1027,7 +1029,7 @@
         StyleTextPropAtom styleAtom = findStyleAtomPresent(headerAtom, rawText.length());
 
         // Store in the appropriate record
-        org.apache.poi.hslf.record.Record oldRecord = null, newRecord;
+        Record oldRecord = null, newRecord;
         if (isUnicode) {
             if (byteAtom != null || charAtom == null) {
                 oldRecord = byteAtom;
@@ -1048,10 +1050,10 @@
         assert (newRecord != null);
 
         RecordContainer _txtbox = headerAtom.getParentRecord();
-        org.apache.poi.hslf.record.Record[] cr = _txtbox.getChildRecords();
+        Record[] cr = _txtbox.getChildRecords();
         int /* headerIdx = -1, */ textIdx = -1, styleIdx = -1;
         for (int i = 0; i < cr.length; i++) {
-            org.apache.poi.hslf.record.Record r = cr[i];
+            Record r = cr[i];
             if (r == headerAtom) {
                 // headerIdx = i;
             } else if (r == oldRecord || r == newRecord) {
@@ -1137,7 +1139,7 @@
 
         // If TextSpecInfoAtom is present, we must update the text size in it,
         // otherwise the ppt will be corrupted
-        for (org.apache.poi.hslf.record.Record r : paragraphs.get(0).getRecords()) {
+        for (Record r : paragraphs.get(0).getRecords()) {
             if (r instanceof TextSpecInfoAtom) {
                 ((TextSpecInfoAtom) r).setParentSize(rawText.length() + 1);
                 break;
@@ -1149,7 +1151,7 @@
         TextHeaderAtom headerAtom = paragraphs.get(0)._headerAtom;
         RecordContainer _txtbox = headerAtom.getParentRecord();
         // remove existing hyperlink records
-        for (org.apache.poi.hslf.record.Record r : _txtbox.getChildRecords()) {
+        for (Record r : _txtbox.getChildRecords()) {
             if (r instanceof InteractiveInfo || r instanceof TxInteractiveInfoAtom) {
                 _txtbox.removeChild(r);
             }
@@ -1395,7 +1397,7 @@
                 }
             }
             if (rv == null || rv.isEmpty()) {
-                LOG.log(POILogger.WARN, "text run not found for OutlineTextRefAtom.TextIndex=" + idx);
+                LOG.atWarn().log("text run not found for OutlineTextRefAtom.TextIndex={}", box(idx));
             }
         } else {
             if (sheet != null) {
@@ -1441,7 +1443,7 @@
      *
      * @param records the records to build from
      */
-    protected static List<List<HSLFTextParagraph>> findTextParagraphs(org.apache.poi.hslf.record.Record[] records) {
+    protected static List<List<HSLFTextParagraph>> findTextParagraphs(Record[] records) {
         List<List<HSLFTextParagraph>> paragraphCollection = new ArrayList<>();
 
         int[] recordIdx = { 0 };
@@ -1453,7 +1455,7 @@
             TextRulerAtom ruler = null;
             MasterTextPropAtom indents = null;
 
-            for (org.apache.poi.hslf.record.Record r : getRecords(records, recordIdx, null)) {
+            for (Record r : getRecords(records, recordIdx, null)) {
                 long rt = r.getRecordType();
                 if (RecordTypes.TextHeaderAtom.typeID == rt) {
                     header = (TextHeaderAtom) r;
@@ -1481,7 +1483,7 @@
             if (tbytes == null && tchars == null) {
                 tbytes = new TextBytesAtom();
                 // don't add record yet - set it in storeText
-                LOG.log(POILogger.INFO, "bytes nor chars atom doesn't exist. Creating dummy record for later saving.");
+                LOG.atInfo().log("bytes nor chars atom doesn't exist. Creating dummy record for later saving.");
             }
 
             String rawText = (tchars != null) ? tchars.getText() : tbytes.getText();
@@ -1510,7 +1512,7 @@
         }
 
         if (paragraphCollection.isEmpty()) {
-            LOG.log(POILogger.DEBUG, "No text records found.");
+            LOG.atDebug().log("No text records found.");
         }
 
         return paragraphCollection;
diff --git a/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFTextRun.java b/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFTextRun.java
index c17f60c..2ffd690 100644
--- a/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFTextRun.java
+++ b/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFTextRun.java
@@ -20,6 +20,8 @@
 import java.awt.Color;
 import java.util.List;
 
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.apache.poi.common.usermodel.fonts.FontGroup;
 import org.apache.poi.common.usermodel.fonts.FontInfo;
 import org.apache.poi.hslf.exceptions.HSLFException;
@@ -36,8 +38,6 @@
 import org.apache.poi.sl.usermodel.TextParagraph;
 import org.apache.poi.sl.usermodel.TextRun;
 import org.apache.poi.sl.usermodel.TextShape;
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
 
 
 /**
@@ -46,7 +46,7 @@
  */
 @SuppressWarnings({"WeakerAccess", "Duplicates", "unused"})
 public final class HSLFTextRun implements TextRun {
-	private static final POILogger LOG = POILogFactory.getLogger(HSLFTextRun.class);
+	private static final Logger LOG = LogManager.getLogger(HSLFTextRun.class);
 
 	/** The TextRun we belong to */
 	private HSLFTextParagraph parentParagraph;
@@ -147,13 +147,13 @@
         final int txtype = parentParagraph.getRunType();
         final HSLFSheet sheet = parentParagraph.getSheet();
         if (sheet == null) {
-            LOG.log(POILogger.ERROR, "Sheet is not available");
+            LOG.atError().log("Sheet is not available");
             return null;
         }
 
         final HSLFMasterSheet master = sheet.getMasterSheet();
         if (master == null) {
-            LOG.log(POILogger.WARN, "MasterSheet is not available");
+            LOG.atWarn().log("MasterSheet is not available");
             return null;
         }
 
@@ -414,7 +414,7 @@
 	 * Sets color of the text, as a int bgr.
 	 * (PowerPoint stores as BlueGreenRed, not the more
 	 *  usual RedGreenBlue)
-	 * @see java.awt.Color
+	 * @see Color
 	 */
 	public void setFontColor(int bgr) {
 		setCharTextPropVal("font.color", bgr);
diff --git a/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFTextShape.java b/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFTextShape.java
index a7fd67b..9a60a2e 100644
--- a/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFTextShape.java
+++ b/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFTextShape.java
@@ -29,6 +29,8 @@
 import java.util.Iterator;
 import java.util.List;
 
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.apache.poi.ddf.AbstractEscherOptRecord;
 import org.apache.poi.ddf.EscherContainerRecord;
 import org.apache.poi.ddf.EscherPropertyTypes;
@@ -54,8 +56,6 @@
 import org.apache.poi.sl.usermodel.TextRun;
 import org.apache.poi.sl.usermodel.TextShape;
 import org.apache.poi.sl.usermodel.VerticalAlignment;
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
 import org.apache.poi.util.Units;
 
 /**
@@ -63,7 +63,7 @@
  */
 public abstract class HSLFTextShape extends HSLFSimpleShape
 implements TextShape<HSLFShape,HSLFTextParagraph> {
-    private static final POILogger LOG = POILogFactory.getLogger(HSLFTextShape.class);
+    private static final Logger LOG = LogManager.getLogger(HSLFTextShape.class);
 
     /**
      * How to anchor the text
@@ -324,7 +324,7 @@
     public Rectangle2D resizeToFitText(Graphics2D graphics) {
         Rectangle2D anchor = getAnchor();
         if(anchor.getWidth() == 0.) {
-            LOG.log(POILogger.WARN, "Width of shape wasn't set. Defaulting to 200px");
+            LOG.atWarn().log("Width of shape wasn't set. Defaulting to 200px");
             anchor.setRect(anchor.getX(), anchor.getY(), 200., anchor.getHeight());
             setAnchor(anchor);
         }
@@ -341,7 +341,7 @@
     /**
     * Returns the type of the text, from the TextHeaderAtom.
     * Possible values can be seen from TextHeaderAtom
-    * @see org.apache.poi.hslf.record.TextHeaderAtom
+    * @see TextHeaderAtom
     */
     public int getRunType() {
         getEscherTextboxWrapper();
@@ -356,7 +356,7 @@
     * Changes the type of the text. Values should be taken
     *  from TextHeaderAtom. No checking is done to ensure you
     *  set this to a valid value!
-    * @see org.apache.poi.hslf.record.TextHeaderAtom
+    * @see TextHeaderAtom
     */
     public void setRunType(int type) {
         getEscherTextboxWrapper();
@@ -641,7 +641,7 @@
             }
 
             if (_paragraphs.isEmpty()) {
-                LOG.log(POILogger.WARN, "TextRecord didn't contained any text lines");
+                LOG.atWarn().log("TextRecord didn't contained any text lines");
             }
         }
 
diff --git a/src/scratchpad/src/org/apache/poi/hsmf/MAPIMessage.java b/src/scratchpad/src/org/apache/poi/hsmf/MAPIMessage.java
index 469bd9b..6e36712 100644
--- a/src/scratchpad/src/org/apache/poi/hsmf/MAPIMessage.java
+++ b/src/scratchpad/src/org/apache/poi/hsmf/MAPIMessage.java
@@ -28,6 +28,8 @@
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.apache.poi.POIReadOnlyDocument;
 import org.apache.poi.hmef.attribute.MAPIRtfAttribute;
 import org.apache.poi.hsmf.datatypes.AttachmentChunks;
@@ -51,8 +53,8 @@
 import org.apache.poi.poifs.filesystem.POIFSFileSystem;
 import org.apache.poi.util.CodePageUtil;
 import org.apache.poi.util.LocaleUtil;
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
+
+import static org.apache.logging.log4j.util.Unbox.box;
 
 /**
  * Reads an Outlook MSG File in and provides hooks into its data structure.
@@ -79,9 +81,9 @@
    }
 
    /** For logging problems we spot with the file */
-   private static final POILogger LOG = POILogFactory.getLogger(MAPIMessage.class);
+   private static final Logger LOG = LogManager.getLogger(MAPIMessage.class);
 
-   private Chunks mainChunks;
+    private Chunks mainChunks;
    private NameIdChunks nameIdChunks;
    private RecipientChunks[] recipientChunks;
    private AttachmentChunks[] attachmentChunks;
@@ -221,8 +223,7 @@
                byte[] htmlBodyBinary = htmlBodyBinaryChunk.getValue();
                return new String(htmlBodyBinary, encoding);
             } catch (UnsupportedEncodingException e) {
-               LOG.log(POILogger.WARN, "HTML body binary: Invalid codepage ID ", codepage, " set for the message via ",
-                  MAPIProperty.INTERNET_CPID, ", ignoring");
+                LOG.atWarn().log("HTML body binary: Invalid codepage ID {} set for the message via {}, ignoring", box(codepage), MAPIProperty.INTERNET_CPID);
             }
          }
          return htmlBodyBinaryChunk.getAs7bitString();
@@ -418,8 +419,7 @@
          String encoding = CodePageUtil.codepageToEncoding(codepage, true);
          generalcodepage = encoding;
        } catch (UnsupportedEncodingException e) {
-         LOG.log(POILogger.WARN, "Invalid codepage ID ", codepage, " set for the message via ",
-             MAPIProperty.MESSAGE_CODEPAGE, ", ignoring");
+           LOG.atWarn().log("Invalid codepage ID {} set for the message via {}, ignoring", box(codepage), MAPIProperty.MESSAGE_CODEPAGE);
        }
      }
      //
@@ -436,8 +436,7 @@
              generalcodepage = encoding;
            }
          } catch (UnsupportedEncodingException e) {
-           LOG.log(POILogger.WARN, "Invalid codepage ID ", codepage, "from locale ID", lcid, " set for the message via ",
-               MAPIProperty.MESSAGE_LOCALE_ID, ", ignoring");
+             LOG.atWarn().log("Invalid codepage ID {}from locale ID{} set for the message via {}, ignoring", box(codepage),box(lcid), MAPIProperty.MESSAGE_LOCALE_ID);
          }
        }
      }
@@ -476,8 +475,7 @@
            bodycodepage = encoding;
          }
        } catch (UnsupportedEncodingException e) {
-         LOG.log(POILogger.WARN, "Invalid codepage ID ", codepage, " set for the message via ",
-             MAPIProperty.INTERNET_CPID, ", ignoring");
+           LOG.atWarn().log("Invalid codepage ID {} set for the message via {}, ignoring", box(codepage), MAPIProperty.INTERNET_CPID);
        }
      }
      //
@@ -617,8 +615,7 @@
       } else if (mc.equalsIgnoreCase("IPM.Post")) {
          return MESSAGE_CLASS.POST;
       } else {
-         LOG.log(POILogger.WARN, "I don't recognize message class '", mc, "'. ",
-                 "Please open an issue on POI's bugzilla");
+          LOG.atWarn().log("I don't recognize message class '{}'. Please open an issue on POI's bugzilla", mc);
          return MESSAGE_CLASS.UNKNOWN;
       }
    }
diff --git a/src/scratchpad/src/org/apache/poi/hsmf/datatypes/AttachmentChunks.java b/src/scratchpad/src/org/apache/poi/hsmf/datatypes/AttachmentChunks.java
index d683ba8..83e5159 100644
--- a/src/scratchpad/src/org/apache/poi/hsmf/datatypes/AttachmentChunks.java
+++ b/src/scratchpad/src/org/apache/poi/hsmf/datatypes/AttachmentChunks.java
@@ -30,16 +30,16 @@
 import java.util.Comparator;
 import java.util.List;
 
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.apache.poi.hsmf.MAPIMessage;
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
 
 /**
  * Collection of convenience chunks for standard parts of the MSG file
  * attachment.
  */
 public class AttachmentChunks implements ChunkGroup {
-    private static final POILogger LOG = POILogFactory.getLogger(AttachmentChunks.class);
+    private static final Logger LOG = LogManager.getLogger(AttachmentChunks.class);
     public static final String PREFIX = "__attach_version1.0_#";
 
     private ByteChunk attachData;
@@ -187,7 +187,7 @@
             } else if (chunk instanceof DirectoryChunk) {
                 attachmentDirectory = (DirectoryChunk) chunk;
             } else {
-                LOG.log(POILogger.ERROR, "Unexpected data chunk of type ", chunk.getEntryName());
+                LOG.atError().log("Unexpected data chunk of type {}", chunk.getEntryName());
             }
         } else if (chunkId == ATTACH_EXTENSION.id) {
             attachExtension = (StringChunk) chunk;
@@ -202,7 +202,7 @@
         } else if (chunkId == ATTACH_CONTENT_ID.id) {
             attachContentId = (StringChunk) chunk;
         } else {
-            LOG.log(POILogger.WARN, "Currently unsupported attachment chunk property will be ignored. ", chunk.getEntryName());
+            LOG.atWarn().log("Currently unsupported attachment chunk property will be ignored. {}", chunk.getEntryName());
         }
 
         // And add to the main list
diff --git a/src/scratchpad/src/org/apache/poi/hsmf/datatypes/Chunks.java b/src/scratchpad/src/org/apache/poi/hsmf/datatypes/Chunks.java
index 82b3c00..041ab37 100644
--- a/src/scratchpad/src/org/apache/poi/hsmf/datatypes/Chunks.java
+++ b/src/scratchpad/src/org/apache/poi/hsmf/datatypes/Chunks.java
@@ -23,8 +23,8 @@
 import java.util.List;
 import java.util.Map;
 
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 
 /**
  * Collection of convenience chunks for standard parts of the MSG file.
@@ -37,7 +37,7 @@
  * TODO Deprecate the public Chunks in favour of Property Lookups
  */
 public final class Chunks implements ChunkGroupWithProperties {
-    private static final POILogger LOG = POILogFactory.getLogger(Chunks.class);
+    private static final Logger LOG = LogManager.getLogger(Chunks.class);
 
     /**
      * Holds all the chunks that were found, indexed by their MAPIProperty.
@@ -262,8 +262,7 @@
         if (messageProperties != null) {
             messageProperties.matchVariableSizedPropertiesToChunks();
         } else {
-            LOG.log(POILogger.WARN,
-                    "Message didn't contain a root list of properties!");
+            LOG.atWarn().log("Message didn't contain a root list of properties!");
         }
     }
 }
diff --git a/src/scratchpad/src/org/apache/poi/hsmf/datatypes/MessageSubmissionChunk.java b/src/scratchpad/src/org/apache/poi/hsmf/datatypes/MessageSubmissionChunk.java
index 20f856d..f1ef43c 100644
--- a/src/scratchpad/src/org/apache/poi/hsmf/datatypes/MessageSubmissionChunk.java
+++ b/src/scratchpad/src/org/apache/poi/hsmf/datatypes/MessageSubmissionChunk.java
@@ -24,11 +24,11 @@
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.apache.poi.hsmf.datatypes.Types.MAPIType;
 import org.apache.poi.util.IOUtils;
 import org.apache.poi.util.LocaleUtil;
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
 
 /**
  * A Chunk that holds the details given back by the server at submission time.
@@ -36,7 +36,7 @@
  * used if you want to cancel a message or similar
  */
 public class MessageSubmissionChunk extends Chunk {
-    private static final POILogger LOG = POILogFactory.getLogger(MessageSubmissionChunk.class);
+    private static final Logger LOG = LogManager.getLogger(MessageSubmissionChunk.class);
     private String rawId;
     private Calendar date;
 
@@ -103,8 +103,7 @@
                         date.set(Calendar.SECOND, Integer.parseInt(m.group(6)));
                         date.clear(Calendar.MILLISECOND);
                     } else {
-                        LOG.log(POILogger.WARN,
-                                "Warning - unable to make sense of date ", dateS);
+                        LOG.atWarn().log("Warning - unable to make sense of date {}", dateS);
                     }
                 }
             }
diff --git a/src/scratchpad/src/org/apache/poi/hsmf/datatypes/PropertiesChunk.java b/src/scratchpad/src/org/apache/poi/hsmf/datatypes/PropertiesChunk.java
index 8800437..6cf9211 100644
--- a/src/scratchpad/src/org/apache/poi/hsmf/datatypes/PropertiesChunk.java
+++ b/src/scratchpad/src/org/apache/poi/hsmf/datatypes/PropertiesChunk.java
@@ -30,6 +30,8 @@
 import java.util.Map;
 import java.util.Map.Entry;
 
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.apache.poi.hsmf.datatypes.PropertyValue.BooleanPropertyValue;
 import org.apache.poi.hsmf.datatypes.PropertyValue.CurrencyPropertyValue;
 import org.apache.poi.hsmf.datatypes.PropertyValue.DoublePropertyValue;
@@ -44,8 +46,8 @@
 import org.apache.poi.util.IOUtils;
 import org.apache.poi.util.LittleEndian;
 import org.apache.poi.util.LittleEndian.BufferUnderrunException;
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
+
+import static org.apache.logging.log4j.util.Unbox.box;
 
 /**
  * <p>
@@ -68,7 +70,7 @@
     public static final int PROPERTIES_FLAG_WRITEABLE = 4;
 
     /** For logging problems we spot with the file */
-    private static final POILogger LOG = POILogFactory.getLogger(PropertiesChunk.class);
+    private static final Logger LOG = LogManager.getLogger(PropertiesChunk.class);
 
     /**
      * Holds properties, indexed by type. If a property is multi-valued, or
@@ -176,7 +178,7 @@
                 if (chunk != null) {
                     cVal.setValue(chunk);
                 } else {
-                    LOG.log(POILogger.WARN, "No chunk found matching Property " + cVal);
+                    LOG.atWarn().log("No chunk found matching Property {}", cVal);
                 }
             }
         }
@@ -200,9 +202,7 @@
                     prop = MAPIProperty.createCustom(id, type, "Unknown " + id);
                 }
                 if (type == null) {
-                    LOG.log(POILogger.WARN, "Invalid type found, expected ",
-                            prop.usualType, " but got ", typeID,
-                            " for property ", prop);
+                    LOG.atWarn().log("Invalid type found, expected {} but got {} for property {}", prop.usualType, box(typeID),prop);
                     going = false;
                     break;
                 }
@@ -220,12 +220,10 @@
                         // We don't know what this property normally is, but it
                         // has come
                         // through with a valid type, so use that
-                        LOG.log(POILogger.INFO, "Property definition for ", prop,
-                            " is missing a type definition, found a value with type ", type);
+                        LOG.atInfo().log("Property definition for {} is missing a type definition, found a value with type {}", prop, type);
                     } else {
                         // Oh dear, something has gone wrong...
-                        LOG.log(POILogger.WARN, "Type mismatch, expected ",
-                            prop.usualType, " but got ", type, " for property ", prop);
+                        LOG.atWarn().log("Type mismatch, expected {} but got {} for property {}", prop.usualType, type, prop);
                         going = false;
                         break;
                     }
@@ -285,8 +283,7 @@
                 }
 
                 if (properties.get(prop) != null) {
-                    LOG.log(POILogger.WARN,
-                            "Duplicate values found for " + prop);
+                    LOG.atWarn().log("Duplicate values found for {}", prop);
                 }
                 properties.put(prop, propVal);
             } catch (BufferUnderrunException e) {
@@ -310,7 +307,7 @@
         baos.close();
 
         // write the header data with the properties declaration
-        directory.createDocument(org.apache.poi.hsmf.datatypes.PropertiesChunk.NAME,
+        directory.createDocument(PropertiesChunk.NAME,
             new ByteArrayInputStream(baos.toByteArray()));
 
         // write the property values
@@ -319,7 +316,7 @@
 
     /**
      * Write the nodes for variable-length data. Those properties are returned by
-     * {@link #writeProperties(java.io.OutputStream)}.
+     * {@link #writeProperties(OutputStream)}.
      *
      * @param directory
      *        The directory.
diff --git a/src/scratchpad/src/org/apache/poi/hsmf/datatypes/RecipientChunks.java b/src/scratchpad/src/org/apache/poi/hsmf/datatypes/RecipientChunks.java
index efcd051..8b37806 100644
--- a/src/scratchpad/src/org/apache/poi/hsmf/datatypes/RecipientChunks.java
+++ b/src/scratchpad/src/org/apache/poi/hsmf/datatypes/RecipientChunks.java
@@ -24,8 +24,8 @@
 import java.util.List;
 import java.util.Map;
 
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 
 /**
  * Collection of convenience chunks for the Recip(ient) part of an outlook file.
@@ -33,7 +33,7 @@
  * If a message has multiple recipients, there will be several of these.
  */
 public final class RecipientChunks implements ChunkGroupWithProperties {
-    private static final POILogger LOG = POILogFactory.getLogger(RecipientChunks.class);
+    private static final Logger LOG = LogManager.getLogger(RecipientChunks.class);
 
     public static final String PREFIX = "__recip_version1.0_#";
 
@@ -88,7 +88,7 @@
             try {
                 recipientNumber = Integer.parseInt(number, 16);
             } catch (NumberFormatException e) {
-                LOG.log(POILogger.ERROR, "Invalid recipient number in name ", name);
+                LOG.atError().log("Invalid recipient number in name {}", name);
             }
         }
     }
@@ -238,7 +238,7 @@
         if (recipientProperties != null) {
             recipientProperties.matchVariableSizedPropertiesToChunks();
         } else {
-            LOG.log(POILogger.WARN, "Recipeints Chunk didn't contain a list of properties!");
+            LOG.atWarn().log("Recipients Chunk didn't contain a list of properties!");
         }
     }
 
diff --git a/src/scratchpad/src/org/apache/poi/hsmf/parsers/POIFSChunkParser.java b/src/scratchpad/src/org/apache/poi/hsmf/parsers/POIFSChunkParser.java
index 5db7ade..086a653 100644
--- a/src/scratchpad/src/org/apache/poi/hsmf/parsers/POIFSChunkParser.java
+++ b/src/scratchpad/src/org/apache/poi/hsmf/parsers/POIFSChunkParser.java
@@ -24,6 +24,8 @@
 import java.util.Objects;
 import java.util.TreeMap;
 
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.apache.poi.hsmf.datatypes.AttachmentChunks;
 import org.apache.poi.hsmf.datatypes.ByteChunk;
 import org.apache.poi.hsmf.datatypes.ByteChunkDeferred;
@@ -46,8 +48,6 @@
 import org.apache.poi.poifs.filesystem.DocumentNode;
 import org.apache.poi.poifs.filesystem.Entry;
 import org.apache.poi.poifs.filesystem.POIFSFileSystem;
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
 
 /**
  * Processes a POIFS of a .msg file into groups of Chunks, such as
@@ -55,7 +55,7 @@
  * data and so on.
  */
 public final class POIFSChunkParser {
-    private static final POILogger LOG = POILogFactory.getLogger(POIFSChunkParser.class);
+    private static final Logger LOG = LogManager.getLogger(POIFSChunkParser.class);
 
     private POIFSChunkParser() {}
 
@@ -149,7 +149,7 @@
             try (DocumentInputStream inp = new DocumentInputStream((DocumentNode) entry)) {
                 chunk.readValue(inp);
             } catch (IOException e) {
-                LOG.log(POILogger.ERROR, "Error reading from part ", entry.getName(), e);
+                LOG.atError().withThrowable(e).log("Error reading from part {}", entry.getName());
             }
         }
 
@@ -234,7 +234,7 @@
                     return new StringChunk(namePrefix, chunkId, type);
                 }
                 // Type of an unsupported type! Skipping...
-                LOG.log(POILogger.WARN, "UNSUPPORTED PROP TYPE ", entryName);
+                LOG.atWarn().log("UNSUPPORTED PROP TYPE {}", entryName);
                 return null;
             }
         }
@@ -249,7 +249,7 @@
             try {
                 multiValueIdx = Long.parseLong(mvidxstr) & 0xFFFFFFFFL;
             } catch (NumberFormatException ignore) {
-                LOG.log(POILogger.WARN, "Can't read multi value idx from entry ", entry.getName());
+                LOG.atWarn().log("Can't read multi value idx from entry {}", entry.getName());
             }
         }
 
@@ -270,7 +270,7 @@
                 chunk = new StringChunk(namePrefix, chunkId, type);
             } else {
                 // Type of an unsupported multivalued type! Skipping...
-                LOG.log(POILogger.WARN, "Unsupported multivalued prop type for entry ", entry.getName());
+                LOG.atWarn().log("Unsupported multivalued prop type for entry {}", entry.getName());
                 return null;
             }
             mc.addChunk((int) multiValueIdx, chunk);
diff --git a/src/scratchpad/src/org/apache/poi/hssf/converter/ExcelToFoConverter.java b/src/scratchpad/src/org/apache/poi/hssf/converter/ExcelToFoConverter.java
index 08b5c4e..50cf542 100644
--- a/src/scratchpad/src/org/apache/poi/hssf/converter/ExcelToFoConverter.java
+++ b/src/scratchpad/src/org/apache/poi/hssf/converter/ExcelToFoConverter.java
@@ -24,6 +24,8 @@
 import javax.xml.transform.dom.DOMSource;
 import javax.xml.transform.stream.StreamResult;
 
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.apache.poi.hpsf.SummaryInformation;
 import org.apache.poi.hssf.usermodel.HSSFCell;
 import org.apache.poi.hssf.usermodel.HSSFCellStyle;
@@ -41,8 +43,6 @@
 import org.apache.poi.ss.usermodel.FillPatternType;
 import org.apache.poi.ss.util.CellRangeAddress;
 import org.apache.poi.util.Beta;
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
 import org.apache.poi.util.XMLHelper;
 import org.w3c.dom.Document;
 import org.w3c.dom.Element;
@@ -60,7 +60,7 @@
 
     private static final float DPI = 72;
 
-    private static final POILogger LOG = POILogFactory.getLogger( ExcelToFoConverter.class );
+    private static final Logger LOG = LogManager.getLogger(ExcelToFoConverter.class);
 
     private static final float PAPER_A4_HEIGHT_INCHES = 29.4f / CM_PER_INCH;
 
@@ -232,10 +232,7 @@
                 value = ErrorEval.getText( cell.getErrorCellValue() );
                 break;
             default:
-                LOG.log(
-                        POILogger.WARN,
-                        "Unexpected cell cachedFormulaResultType ("
-                                + cell.getCachedFormulaResultType() + ")" );
+                LOG.atWarn().log("Unexpected cell cachedFormulaResultType ({})", cell.getCachedFormulaResultType());
                 value = AbstractExcelUtils.EMPTY;
                 break;
             }
@@ -253,8 +250,7 @@
             value = ErrorEval.getText( cell.getErrorCellValue() );
             break;
         default:
-            LOG.log( POILogger.WARN,
-                    "Unexpected cell type (" + cell.getCellType() + ")" );
+            LOG.atWarn().log("Unexpected cell type ({})", cell.getCellType());
             return true;
         }
 
diff --git a/src/scratchpad/src/org/apache/poi/hssf/converter/ExcelToHtmlConverter.java b/src/scratchpad/src/org/apache/poi/hssf/converter/ExcelToHtmlConverter.java
index ea6bf76..0110c71 100644
--- a/src/scratchpad/src/org/apache/poi/hssf/converter/ExcelToHtmlConverter.java
+++ b/src/scratchpad/src/org/apache/poi/hssf/converter/ExcelToHtmlConverter.java
@@ -30,6 +30,8 @@
 import javax.xml.transform.dom.DOMSource;
 import javax.xml.transform.stream.StreamResult;
 
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.apache.poi.hpsf.SummaryInformation;
 import org.apache.poi.hssf.usermodel.HSSFCell;
 import org.apache.poi.hssf.usermodel.HSSFCellStyle;
@@ -44,8 +46,6 @@
 import org.apache.poi.ss.usermodel.BorderStyle;
 import org.apache.poi.ss.util.CellRangeAddress;
 import org.apache.poi.util.Beta;
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
 import org.apache.poi.util.XMLHelper;
 import org.w3c.dom.Document;
 import org.w3c.dom.Element;
@@ -58,7 +58,7 @@
  */
 @Beta
 public class ExcelToHtmlConverter extends AbstractExcelConverter {
-    private static final POILogger LOG = POILogFactory.getLogger( ExcelToHtmlConverter.class );
+    private static final Logger LOG = LogManager.getLogger(ExcelToHtmlConverter.class);
 
     /**
      * Java main() interface to interact with {@link ExcelToHtmlConverter}
@@ -322,10 +322,7 @@
                 value = ErrorEval.getText( cell.getErrorCellValue() );
                 break;
             default:
-                LOG.log(
-                        POILogger.WARN,
-                        "Unexpected cell cachedFormulaResultType ("
-                                + cell.getCachedFormulaResultType() + ")" );
+                LOG.atWarn().log("Unexpected cell cachedFormulaResultType ({})", cell.getCachedFormulaResultType());
                 value = AbstractExcelUtils.EMPTY;
                 break;
             }
@@ -343,8 +340,7 @@
             value = ErrorEval.getText( cell.getErrorCellValue() );
             break;
         default:
-            LOG.log( POILogger.WARN,
-                    "Unexpected cell type (" + cell.getCellType() + ")" );
+            LOG.atWarn().log("Unexpected cell type ({})", cell.getCellType());
             return true;
         }
 
diff --git a/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfBitmapDib.java b/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfBitmapDib.java
index 7af8322..9159780 100644
--- a/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfBitmapDib.java
+++ b/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfBitmapDib.java
@@ -36,6 +36,8 @@
 
 import javax.imageio.ImageIO;
 
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.apache.poi.common.usermodel.GenericRecord;
 import org.apache.poi.hwmf.usermodel.HwmfPicture;
 import org.apache.poi.util.GenericRecordJsonWriter;
@@ -43,8 +45,6 @@
 import org.apache.poi.util.LittleEndian;
 import org.apache.poi.util.LittleEndianConsts;
 import org.apache.poi.util.LittleEndianInputStream;
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
 import org.apache.poi.util.RecordFormatException;
 
 /**
@@ -52,7 +52,7 @@
  */
 public class HwmfBitmapDib implements GenericRecord {
 
-    private static final POILogger LOG = POILogFactory.getLogger(HwmfBitmapDib.class);
+    private static final Logger LOG = LogManager.getLogger(HwmfBitmapDib.class);
     private static final int BMP_HEADER_SIZE = 14;
     private static final int MAX_RECORD_LENGTH = HwmfPicture.MAX_RECORD_LENGTH;
 
@@ -479,11 +479,11 @@
         try {
             bi = ImageIO.read(getBMPStream());
         } catch (IOException|RuntimeException e) {
-            LOG.log(POILogger.ERROR, "invalid bitmap data - returning placeholder image");
+            LOG.atError().log("invalid bitmap data - returning placeholder image");
             return getPlaceholder();
         }
 
-        if (foreground != null && background != null && headerBitCount == HwmfBitmapDib.BitCount.BI_BITCOUNT_1) {
+        if (foreground != null && background != null && headerBitCount == BitCount.BI_BITCOUNT_1) {
             IndexColorModel cmOld = (IndexColorModel)bi.getColorModel();
             int fg = foreground.getRGB();
             int bg = background.getRGB() & (hasAlpha ? 0xFFFFFF : 0xFFFFFFFF);
diff --git a/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfText.java b/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfText.java
index c806bef..6f72d28 100644
--- a/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfText.java
+++ b/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfText.java
@@ -31,6 +31,8 @@
 import java.util.Map;
 import java.util.function.Supplier;
 
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.apache.poi.common.usermodel.GenericRecord;
 import org.apache.poi.hwmf.draw.HwmfDrawProperties;
 import org.apache.poi.hwmf.draw.HwmfGraphics;
@@ -44,11 +46,9 @@
 import org.apache.poi.util.LittleEndianConsts;
 import org.apache.poi.util.LittleEndianInputStream;
 import org.apache.poi.util.LocaleUtil;
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
 
 public class HwmfText {
-    private static final POILogger LOG = POILogFactory.getLogger(HwmfText.class);
+    private static final Logger LOG = LogManager.getLogger(HwmfText.class);
     private static final int MAX_RECORD_LENGTH = 1_000_000;
 
     /**
@@ -430,13 +430,13 @@
             size += rawTextBytes.length;
 
             if (size >= remainingRecordSize) {
-                LOG.log(POILogger.INFO, "META_EXTTEXTOUT doesn't contain character tracking info");
+                LOG.atInfo().log("META_EXTTEXTOUT doesn't contain character tracking info");
                 return size;
             }
 
             int dxLen = Math.min(stringLength, (remainingRecordSize-size)/LittleEndianConsts.SHORT_SIZE);
             if (dxLen < stringLength) {
-                LOG.log(POILogger.WARN, "META_EXTTEXTOUT tracking info doesn't cover all characters");
+                LOG.atWarn().log("META_EXTTEXTOUT tracking info doesn't cover all characters");
             }
 
             for (int i=0; i<dxLen; i++) {
diff --git a/src/scratchpad/src/org/apache/poi/hwmf/usermodel/HwmfPicture.java b/src/scratchpad/src/org/apache/poi/hwmf/usermodel/HwmfPicture.java
index 76096de..0fb9637 100644
--- a/src/scratchpad/src/org/apache/poi/hwmf/usermodel/HwmfPicture.java
+++ b/src/scratchpad/src/org/apache/poi/hwmf/usermodel/HwmfPicture.java
@@ -34,6 +34,8 @@
 import java.util.Spliterator;
 import java.util.function.Supplier;
 
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.apache.poi.common.usermodel.GenericRecord;
 import org.apache.poi.hwmf.draw.HwmfDrawProperties;
 import org.apache.poi.hwmf.draw.HwmfGraphics;
@@ -48,8 +50,6 @@
 import org.apache.poi.util.IOUtils;
 import org.apache.poi.util.LittleEndianInputStream;
 import org.apache.poi.util.LocaleUtil;
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
 import org.apache.poi.util.RecordFormatException;
 import org.apache.poi.util.Units;
 
@@ -57,7 +57,7 @@
     /** Max. record length - processing longer records will throw an exception */
     public static final int MAX_RECORD_LENGTH = 50_000_000;
 
-    private static final POILogger LOG = POILogFactory.getLogger(HwmfPicture.class);
+    private static final Logger LOG = LogManager.getLogger(HwmfPicture.class);
 
     final List<HwmfRecord> records = new ArrayList<>();
     final HwmfPlaceableHeader placeableHeader;
@@ -85,7 +85,7 @@
                     recordSize = (int)recordSizeLong;
                     recordFunction = leis.readShort();
                 } catch (Exception e) {
-                    LOG.log(POILogger.ERROR, "unexpected eof - wmf file was truncated");
+                    LOG.atError().log("unexpected eof - wmf file was truncated");
                     break;
                 }
                 // 4 bytes (recordSize) + 2 bytes (recordFunction)
diff --git a/src/scratchpad/src/org/apache/poi/hwpf/HWPFOldDocument.java b/src/scratchpad/src/org/apache/poi/hwpf/HWPFOldDocument.java
index dd44d45..a5a3d44 100644
--- a/src/scratchpad/src/org/apache/poi/hwpf/HWPFOldDocument.java
+++ b/src/scratchpad/src/org/apache/poi/hwpf/HWPFOldDocument.java
@@ -21,6 +21,8 @@
 import java.io.OutputStream;
 import java.nio.charset.Charset;
 
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.apache.poi.common.usermodel.fonts.FontCharset;
 import org.apache.poi.hwpf.model.ComplexFileTable;
 import org.apache.poi.hwpf.model.FontTable;
@@ -41,8 +43,6 @@
 import org.apache.poi.util.IOUtils;
 import org.apache.poi.util.LittleEndian;
 import org.apache.poi.util.NotImplemented;
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
 import org.apache.poi.util.StringUtil;
 
 /**
@@ -51,7 +51,7 @@
  */
 public class HWPFOldDocument extends HWPFDocumentCore {
 
-    private static final POILogger LOG = POILogFactory.getLogger( HWPFOldDocument.class );
+    private static final Logger LOG = LogManager.getLogger(HWPFOldDocument.class);
 
     //arbitrarily selected; may need to increase
     private static final int MAX_RECORD_LENGTH = 10_000_000;
@@ -114,7 +114,7 @@
                 //if there was a problem with the guessed charset and the length of the
                 //textpiece, back off to win1252. This is effectively what we used to do.
                 tp = buildTextPiece(StringUtil.WIN_1252);
-                LOG.log(POILogger.WARN, "Error with "+guessedCharset +". Backing off to Windows-1252");
+                LOG.atWarn().log("Error with {}. Backing off to Windows-1252", guessedCharset);
             }
             tpt.add(tp);
 
@@ -205,7 +205,7 @@
                 return wmfCharset.getCharset();
             }
         }
-        LOG.log(POILogger.WARN, "Couldn't find a defined charset; backing off to cp1252");
+        LOG.atWarn().log("Couldn't find a defined charset; backing off to cp1252");
         //if all else fails
         return DEFAULT_CHARSET;
     }
diff --git a/src/scratchpad/src/org/apache/poi/hwpf/converter/AbstractWordConverter.java b/src/scratchpad/src/org/apache/poi/hwpf/converter/AbstractWordConverter.java
index 741ee21..1ff262d 100644
--- a/src/scratchpad/src/org/apache/poi/hwpf/converter/AbstractWordConverter.java
+++ b/src/scratchpad/src/org/apache/poi/hwpf/converter/AbstractWordConverter.java
@@ -27,6 +27,8 @@
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.apache.poi.hpsf.SummaryInformation;
 import org.apache.poi.hwpf.HWPFDocument;
 import org.apache.poi.hwpf.HWPFDocumentCore;
@@ -50,11 +52,11 @@
 import org.apache.poi.poifs.filesystem.Entry;
 import org.apache.poi.util.Beta;
 import org.apache.poi.util.Internal;
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
 import org.w3c.dom.Document;
 import org.w3c.dom.Element;
 
+import static org.apache.logging.log4j.util.Unbox.box;
+
 @Beta
 public abstract class AbstractWordConverter {
     private static class DeadFieldBoundaries {
@@ -115,7 +117,7 @@
     private static final int FIELD_HYPERLINK = 88;
 
 
-    private static final POILogger LOG = POILogFactory.getLogger(AbstractWordConverter.class);
+    private static final Logger LOG = LogManager.getLogger(AbstractWordConverter.class);
 
     private static final Pattern PATTERN_HYPERLINK_EXTERNAL = Pattern
         .compile("^[ \\t\\r\\n]*HYPERLINK \"(.*)\".*$");
@@ -399,10 +401,8 @@
 
         if (previous != range.getStartOffset()) {
             if (previous > range.getEndOffset()) {
-                LOG.log(POILogger.WARN, "Latest structure in ", range,
-                    " ended at #", previous, " after range boundaries [",
-                    range.getStartOffset(), "; ", range.getEndOffset(),
-                    ")");
+                LOG.atWarn().log("Latest structure in {} ended at #{} after range boundaries [{}; {})",
+                        range, box(previous),box(range.getStartOffset()),box(range.getEndOffset()));
                 return true;
             }
 
@@ -595,7 +595,7 @@
             debug.append(range.getCharacterRun(i));
             debug.append("\n");
         }
-        LOG.log(POILogger.WARN, debug);
+        LOG.atWarn().log(debug);
 
         Range deadFieldValueSubrage = new Range(range.getCharacterRun(
             separatorMark).getStartOffset() + 1, range.getCharacterRun(
@@ -621,7 +621,7 @@
                 processDocumentInformation(summaryInformation);
             }
         } catch (Exception exc) {
-            LOG.log(POILogger.WARN, "Unable to process document summary information: ", exc, exc);
+            LOG.atWarn().withThrowable(exc).log("Unable to process document summary information");
         }
 
         final Range docRange = wordDocument.getRange();
@@ -656,8 +656,7 @@
         OfficeDrawing officeDrawing = doc.getOfficeDrawingsMain()
             .getOfficeDrawingAt(characterRun.getStartOffset());
         if (officeDrawing == null) {
-            LOG.log(POILogger.WARN, "Characters #", characterRun,
-                " references missing drawn object");
+            LOG.atWarn().log("Characters #{} references missing drawn object", characterRun);
             return;
         }
 
@@ -715,8 +714,7 @@
             }
             case FIELD_EMBEDDED_OBJECT: {
                 if (!field.hasSeparator()) {
-                    LOG.log(POILogger.WARN, parentRange, " contains ", field,
-                        " with 'Embedded Object' but without separator mark");
+                    LOG.atWarn().log("{} contains {} with 'Embedded Object' but without separator mark", parentRange, field);
                     return;
                 }
 
@@ -790,7 +788,7 @@
             }
         }
 
-        LOG.log(POILogger.WARN, parentRange, " contains ", field, " with unsupported type or format");
+        LOG.atWarn().log("{} contains {} with unsupported type or format", parentRange, field);
         processCharacters(wordDocument, currentTableLevel,
             field.secondSubrange(parentRange), currentBlock);
     }
@@ -881,14 +879,14 @@
         Element block) {
         Entry entry = doc.getObjectsPool().getObjectById("_" + characterRun.getPicOffset());
         if (entry == null) {
-            LOG.log(POILogger.WARN, "Referenced OLE2 object '", characterRun.getPicOffset(), "' not found in ObjectPool");
+            LOG.atWarn().log("Referenced OLE2 object '{}' not found in ObjectPool", box(characterRun.getPicOffset()));
             return false;
         }
 
         try {
             return processOle2(doc, block, entry);
         } catch (Exception exc) {
-            LOG.log(POILogger.WARN, "Unable to convert internal OLE2 object '", characterRun.getPicOffset(), "': ", exc, exc);
+            LOG.atWarn().withThrowable(exc).log("Unable to convert internal OLE2 object '{}'", box(characterRun.getPicOffset()));
             return false;
         }
     }
@@ -943,7 +941,7 @@
                     processParagraph(wordDocument, flow, currentTableLevel, paragraph, label);
                     processed = true;
                 } catch (Exception exc) {
-                    LOG.log(POILogger.WARN, "Can't process paragraph as list entry, will be processed without list information", exc);
+                    LOG.atWarn().withThrowable(exc).log("Can't process paragraph as list entry, will be processed without list information");
                 }
             }
 
diff --git a/src/scratchpad/src/org/apache/poi/hwpf/converter/AbstractWordUtils.java b/src/scratchpad/src/org/apache/poi/hwpf/converter/AbstractWordUtils.java
index ab89c92..1f633c5 100644
--- a/src/scratchpad/src/org/apache/poi/hwpf/converter/AbstractWordUtils.java
+++ b/src/scratchpad/src/org/apache/poi/hwpf/converter/AbstractWordUtils.java
@@ -26,6 +26,8 @@
 import java.util.Set;
 import java.util.TreeSet;
 
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.apache.poi.hwpf.HWPFDocument;
 import org.apache.poi.hwpf.HWPFDocumentCore;
 import org.apache.poi.hwpf.HWPFOldDocument;
@@ -38,20 +40,20 @@
 import org.apache.poi.poifs.filesystem.DirectoryNode;
 import org.apache.poi.poifs.filesystem.POIFSFileSystem;
 import org.apache.poi.util.Beta;
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
 import org.w3c.dom.Attr;
 import org.w3c.dom.Element;
 import org.w3c.dom.NamedNodeMap;
 import org.w3c.dom.Node;
 import org.w3c.dom.NodeList;
 
+import static org.apache.logging.log4j.util.Unbox.box;
+
 @Beta
 public class AbstractWordUtils
 {
     static final String EMPTY = "";
 
-    private static final POILogger LOG = POILogFactory.getLogger( AbstractWordUtils.class );
+    private static final Logger LOG = LogManager.getLogger(AbstractWordUtils.class);
 
     public static final float TWIPS_PER_INCH = 1440.0f;
     public static final int TWIPS_PER_PT = 20;
@@ -417,7 +419,7 @@
         case 2057:
             return "en-uk";
         default:
-            LOG.log( POILogger.WARN, "Uknown or unmapped language code: ", languageCode);
+            LOG.atWarn().log("Unknown or unmapped language code: {}", box(languageCode));
             return EMPTY;
         }
     }
@@ -426,7 +428,7 @@
     {
 
         if ( format != 0 )
-        	LOG.log( POILogger.INFO, "NYI: toListItemNumberLabel(): ", format );
+        	LOG.atInfo().log("NYI: toListItemNumberLabel(): {}", box(format));
 
         return String.valueOf( number );
     }
diff --git a/src/scratchpad/src/org/apache/poi/hwpf/converter/WordToFoConverter.java b/src/scratchpad/src/org/apache/poi/hwpf/converter/WordToFoConverter.java
index fc82295..d917084 100644
--- a/src/scratchpad/src/org/apache/poi/hwpf/converter/WordToFoConverter.java
+++ b/src/scratchpad/src/org/apache/poi/hwpf/converter/WordToFoConverter.java
@@ -16,6 +16,7 @@
 ==================================================================== */
 package org.apache.poi.hwpf.converter;
 
+import static org.apache.logging.log4j.util.Unbox.box;
 import static org.apache.poi.hwpf.converter.AbstractWordUtils.TWIPS_PER_INCH;
 import static org.apache.poi.hwpf.converter.AbstractWordUtils.isNotEmpty;
 import static org.apache.poi.hwpf.converter.AbstractWordUtils.loadDoc;
@@ -33,6 +34,8 @@
 import javax.xml.transform.dom.DOMSource;
 import javax.xml.transform.stream.StreamResult;
 
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.apache.poi.hpsf.SummaryInformation;
 import org.apache.poi.hwpf.HWPFDocument;
 import org.apache.poi.hwpf.HWPFDocumentCore;
@@ -48,8 +51,6 @@
 import org.apache.poi.hwpf.usermodel.TableCell;
 import org.apache.poi.hwpf.usermodel.TableRow;
 import org.apache.poi.util.Beta;
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
 import org.apache.poi.util.XMLHelper;
 import org.w3c.dom.Document;
 import org.w3c.dom.Element;
@@ -64,7 +65,7 @@
 public class WordToFoConverter extends AbstractWordConverter
 {
 
-    private static final POILogger LOG = POILogFactory.getLogger( WordToFoConverter.class );
+    private static final Logger LOG = LogManager.getLogger(WordToFoConverter.class);
 
     /**
      * Java main() interface to interact with {@link WordToFoConverter}
@@ -574,11 +575,7 @@
         }
         else
         {
-            LOG.log(
-                    POILogger.WARN,
-                    "Table without body starting on offset ",
-                            table.getStartOffset(), " -- ",
-                            table.getEndOffset() );
+            LOG.atWarn().log("Table without body starting on offset {} -- {}", box(table.getStartOffset()),box(table.getEndOffset()));
         }
     }
 
@@ -587,8 +584,7 @@
         // making sure ID used once
         if ( usedIds.contains( id ) )
         {
-            LOG.log( POILogger.WARN,
-                    "Tried to create element with same ID '", id, "'. Skipped" );
+            LOG.atWarn().log("Tried to create element with same ID '{}'. Skipped", id);
             return false;
         }
 
diff --git a/src/scratchpad/src/org/apache/poi/hwpf/converter/WordToHtmlConverter.java b/src/scratchpad/src/org/apache/poi/hwpf/converter/WordToHtmlConverter.java
index 5a96806..a60d504 100644
--- a/src/scratchpad/src/org/apache/poi/hwpf/converter/WordToHtmlConverter.java
+++ b/src/scratchpad/src/org/apache/poi/hwpf/converter/WordToHtmlConverter.java
@@ -16,6 +16,7 @@
 ==================================================================== */
 package org.apache.poi.hwpf.converter;
 
+import static org.apache.logging.log4j.util.Unbox.box;
 import static org.apache.poi.hwpf.converter.AbstractWordUtils.TWIPS_PER_INCH;
 
 import java.io.File;
@@ -33,6 +34,8 @@
 import javax.xml.transform.dom.DOMSource;
 import javax.xml.transform.stream.StreamResult;
 
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.apache.poi.hpsf.SummaryInformation;
 import org.apache.poi.hwpf.HWPFDocument;
 import org.apache.poi.hwpf.HWPFDocumentCore;
@@ -48,8 +51,6 @@
 import org.apache.poi.hwpf.usermodel.TableCell;
 import org.apache.poi.hwpf.usermodel.TableRow;
 import org.apache.poi.util.Beta;
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
 import org.apache.poi.util.XMLHelper;
 import org.w3c.dom.Document;
 import org.w3c.dom.Element;
@@ -81,7 +82,7 @@
         }
     }
 
-    private static final POILogger LOG = POILogFactory.getLogger( WordToHtmlConverter.class );
+    private static final Logger LOG = LogManager.getLogger(WordToHtmlConverter.class);
 
     private final Deque<BlockProperies> blocksProperies = new LinkedList<>();
 
@@ -737,9 +738,7 @@
         }
         else
         {
-            LOG.log( POILogger.WARN, "Table without body starting at [",
-                    Integer.valueOf( table.getStartOffset() ), "; ",
-                    Integer.valueOf( table.getEndOffset() ), ")" );
+            LOG.atWarn().log("Table without body starting at [{}; {})", box(table.getStartOffset()),box(table.getEndOffset()));
         }
     }
 
diff --git a/src/scratchpad/src/org/apache/poi/hwpf/converter/WordToTextConverter.java b/src/scratchpad/src/org/apache/poi/hwpf/converter/WordToTextConverter.java
index 8ee50e5..cebc55b 100644
--- a/src/scratchpad/src/org/apache/poi/hwpf/converter/WordToTextConverter.java
+++ b/src/scratchpad/src/org/apache/poi/hwpf/converter/WordToTextConverter.java
@@ -30,6 +30,8 @@
 import javax.xml.transform.dom.DOMSource;
 import javax.xml.transform.stream.StreamResult;
 
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.apache.poi.hpsf.SummaryInformation;
 import org.apache.poi.hwpf.HWPFDocument;
 import org.apache.poi.hwpf.HWPFDocumentCore;
@@ -46,8 +48,6 @@
 import org.apache.poi.poifs.filesystem.DirectoryNode;
 import org.apache.poi.poifs.filesystem.Entry;
 import org.apache.poi.util.Beta;
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
 import org.apache.poi.util.XMLHelper;
 import org.w3c.dom.Document;
 import org.w3c.dom.Element;
@@ -55,7 +55,7 @@
 @Beta
 public class WordToTextConverter extends AbstractWordConverter
 {
-    private static final POILogger LOG = POILogFactory.getLogger( WordToTextConverter.class );
+    private static final Logger LOG = LogManager.getLogger(WordToTextConverter.class);
 
     public static String getText( DirectoryNode root ) throws Exception
     {
@@ -351,10 +351,8 @@
         catch ( Exception exc )
         {
             // no extractor in classpath
-            LOG.log( POILogger.WARN, "There is an OLE object entry '",
-                    entry.getName(),
-                    "', but there is no text extractor for this object type ",
-                    "or text extractor factory is not available: ", "", exc );
+            LOG.atWarn().withThrowable(exc).log("There is an OLE object entry '{}', but there is no text " +
+                    "extractor for this object type or text extractor factory is not available", entry.getName());
             return false;
         }
 
@@ -370,9 +368,7 @@
         }
         catch ( Exception exc )
         {
-            LOG.log( POILogger.ERROR,
-                    "Unable to extract text from OLE entry '", entry.getName(),
-                    "': ", exc, exc );
+            LOG.atError().withThrowable(exc).log("Unable to extract text from OLE entry '{}'", entry.getName());
             return false;
         }
     }
diff --git a/src/scratchpad/src/org/apache/poi/hwpf/model/BookmarksTables.java b/src/scratchpad/src/org/apache/poi/hwpf/model/BookmarksTables.java
index b5c2f7f..1ffdbc6 100644
--- a/src/scratchpad/src/org/apache/poi/hwpf/model/BookmarksTables.java
+++ b/src/scratchpad/src/org/apache/poi/hwpf/model/BookmarksTables.java
@@ -22,15 +22,17 @@
 import java.util.Arrays;
 import java.util.List;
 
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.apache.poi.hwpf.model.types.BKFAbstractType;
 import org.apache.poi.util.Internal;
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
+
+import static org.apache.logging.log4j.util.Unbox.box;
 
 @Internal
 public class BookmarksTables
 {
-    private static final POILogger LOG = POILogFactory.getLogger( BookmarksTables.class );
+    private static final Logger LOG = LogManager.getLogger(BookmarksTables.class);
 
     private PlexOfCps descriptorsFirst = new PlexOfCps( 4 );
 
@@ -53,8 +55,7 @@
             GenericPropertyNode endNode = descriptorsLim.getProperty( i );
             if ( startNode.getStart() == endNode.getStart() )
             {
-                LOG.log( POILogger.DEBUG, "Removing bookmark #",
-                        Integer.valueOf( i ), "..." );
+                LOG.atDebug().log("Removing bookmark #{}...", box(i));
                 remove( i );
                 i--;
                 continue;
diff --git a/src/scratchpad/src/org/apache/poi/hwpf/model/CHPBinTable.java b/src/scratchpad/src/org/apache/poi/hwpf/model/CHPBinTable.java
index 9559f56..178186b 100644
--- a/src/scratchpad/src/org/apache/poi/hwpf/model/CHPBinTable.java
+++ b/src/scratchpad/src/org/apache/poi/hwpf/model/CHPBinTable.java
@@ -31,6 +31,8 @@
 import java.util.Map;
 import java.util.Set;
 
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.apache.poi.hwpf.model.io.HWPFFileSystem;
 import org.apache.poi.hwpf.sprm.SprmBuffer;
 import org.apache.poi.hwpf.sprm.SprmIterator;
@@ -38,8 +40,9 @@
 import org.apache.poi.poifs.common.POIFSConstants;
 import org.apache.poi.util.Internal;
 import org.apache.poi.util.LittleEndian;
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
+
+import static java.lang.System.currentTimeMillis;
+import static org.apache.logging.log4j.util.Unbox.box;
 
 /**
  * This class holds all of the character formatting properties.
@@ -49,9 +52,9 @@
 @Internal
 public class CHPBinTable
 {
-    private static final POILogger LOG = POILogFactory.getLogger( CHPBinTable.class );
+    private static final Logger LOG = LogManager.getLogger(CHPBinTable.class);
 
-  /** List of character properties.*/
+    /** List of character properties.*/
   protected List<CHPX> _textRuns = new ArrayList<>();
 
   public CHPBinTable()
@@ -77,7 +80,7 @@
     public CHPBinTable( byte[] documentStream, byte[] tableStream, int offset,
             int size, CharIndexTranslator translator )
     {
-        long start = System.currentTimeMillis();
+        long start = currentTimeMillis();
         /*
          * Page 35:
          *
@@ -105,20 +108,18 @@
                     _textRuns.add( chpx );
             }
     }
-        LOG.log( POILogger.DEBUG, "CHPX FKPs loaded in ",
-                Long.valueOf( System.currentTimeMillis() - start ), " ms (",
-                Integer.valueOf( _textRuns.size() ), " elements)" );
+        LOG.atDebug().log("CHPX FKPs loaded in {} ms ({} elements)", box(currentTimeMillis() - start),box(_textRuns.size()));
 
         if ( _textRuns.isEmpty() )
         {
-            LOG.log( POILogger.WARN, "CHPX FKPs are empty" );
+            LOG.atWarn().log("CHPX FKPs are empty");
             _textRuns.add( new CHPX( 0, 0, new SprmBuffer( 0 ) ) );
         }
     }
 
     public void rebuild( ComplexFileTable complexFileTable )
     {
-        long start = System.currentTimeMillis();
+        long start = currentTimeMillis();
 
         if ( complexFileTable != null )
         {
@@ -135,8 +136,7 @@
 
                 if ( igrpprl < 0 || igrpprl >= sprmBuffers.length )
                 {
-                    LOG.log( POILogger.WARN, textPiece
-                            + "'s PRM references to unknown grpprl" );
+                    LOG.atWarn().log("{}'s PRM references to unknown grpprl", textPiece);
                     continue;
                 }
 
@@ -162,20 +162,15 @@
                     _textRuns.add( chpx );
                 }
             }
-            LOG.log( POILogger.DEBUG,
-                    "Merged with CHPX from complex file table in ",
-                    Long.valueOf( System.currentTimeMillis() - start ),
-                    " ms (", Integer.valueOf( _textRuns.size() ),
-                    " elements in total)" );
-            start = System.currentTimeMillis();
+            LOG.atDebug().log("Merged with CHPX from complex file table in {} ms ({} elements in total)", box(currentTimeMillis() - start),box(_textRuns.size()));
+            start = currentTimeMillis();
         }
 
         List<CHPX> oldChpxSortedByStartPos = new ArrayList<>(_textRuns);
         oldChpxSortedByStartPos.sort(PropertyNode.StartComparator);
 
-        LOG.log( POILogger.DEBUG, "CHPX sorted by start position in ",
-                Long.valueOf( System.currentTimeMillis() - start ), " ms" );
-        start = System.currentTimeMillis();
+        LOG.atDebug().log("CHPX sorted by start position in {} ms", box(currentTimeMillis() - start));
+        start = currentTimeMillis();
 
         final Map<CHPX, Integer> chpxToFileOrder = new IdentityHashMap<>();
         {
@@ -195,9 +190,8 @@
             }
         };
 
-        LOG.log( POILogger.DEBUG, "CHPX's order map created in ",
-                Long.valueOf( System.currentTimeMillis() - start ), " ms" );
-        start = System.currentTimeMillis();
+        LOG.atDebug().log("CHPX's order map created in {} ms", box(currentTimeMillis() - start));
+        start = currentTimeMillis();
 
         List<Integer> textRunsBoundariesList;
         {
@@ -213,9 +207,8 @@
             Collections.sort( textRunsBoundariesList );
         }
 
-        LOG.log( POILogger.DEBUG, "Texts CHPX boundaries collected in ",
-                Long.valueOf( System.currentTimeMillis() - start ), " ms" );
-        start = System.currentTimeMillis();
+        LOG.atDebug().log("Texts CHPX boundaries collected in {} ms", box(currentTimeMillis() - start));
+        start = currentTimeMillis();
 
         List<CHPX> newChpxs = new LinkedList<>();
         int lastTextRunStart = 0;
@@ -253,10 +246,7 @@
 
             if ( chpxs.size() == 0 )
             {
-                LOG.log( POILogger.WARN, "Text piece [",
-                        Integer.valueOf( startInclusive ), "; ",
-                        Integer.valueOf(boundary),
-                        ") has no CHPX. Creating new one." );
+                LOG.atWarn().log("Text piece [{}; {}) has no CHPX. Creating new one.", box(startInclusive),box(boundary));
                 // create it manually
                 CHPX chpx = new CHPX( startInclusive, boundary,
                         new SprmBuffer( 0 ) );
@@ -290,10 +280,8 @@
         }
         this._textRuns = new ArrayList<>(newChpxs);
 
-        LOG.log( POILogger.DEBUG, "CHPX rebuilded in ",
-                Long.valueOf( System.currentTimeMillis() - start ), " ms (",
-                Integer.valueOf( _textRuns.size() ), " elements)" );
-        start = System.currentTimeMillis();
+        LOG.atDebug().log("CHPX rebuilt in {} ms ({} elements)", box(currentTimeMillis() - start),box(_textRuns.size()));
+        start = currentTimeMillis();
 
         CHPX previous = null;
         for ( Iterator<CHPX> iterator = _textRuns.iterator(); iterator
@@ -318,9 +306,7 @@
             previous = current;
         }
 
-        LOG.log( POILogger.DEBUG, "CHPX compacted in ",
-                Long.valueOf( System.currentTimeMillis() - start ), " ms (",
-                Integer.valueOf( _textRuns.size() ), " elements)" );
+        LOG.atDebug().log("CHPX compacted in {} ms ({} elements)", box(currentTimeMillis() - start),box(_textRuns.size()));
     }
 
     private static int binarySearch( List<CHPX> chpxs, int startPosition )
diff --git a/src/scratchpad/src/org/apache/poi/hwpf/model/FIBFieldHandler.java b/src/scratchpad/src/org/apache/poi/hwpf/model/FIBFieldHandler.java
index 83ca143..227df33 100644
--- a/src/scratchpad/src/org/apache/poi/hwpf/model/FIBFieldHandler.java
+++ b/src/scratchpad/src/org/apache/poi/hwpf/model/FIBFieldHandler.java
@@ -24,11 +24,13 @@
 import java.util.HashSet;
 import java.util.Map;
 
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.apache.poi.util.Internal;
 import org.apache.poi.util.LittleEndian;
 import org.apache.poi.util.LittleEndianConsts;
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
+
+import static org.apache.logging.log4j.util.Unbox.box;
 
 @Internal
 public final class FIBFieldHandler
@@ -145,7 +147,7 @@
   public static final int STTBLISTNAMES = 91;
   public static final int STTBFUSSR = 92;
 
-  private static final POILogger log = POILogFactory.getLogger(FIBFieldHandler.class);
+  private static final Logger LOGGER = LogManager.getLogger(FIBFieldHandler.class);
 
   private static final int FIELD_SIZE = LittleEndianConsts.INT_SIZE * 2;
 
@@ -171,9 +173,7 @@
         {
           if (dsOffset + dsSize > tableStream.length)
           {
-              log.log(POILogger.WARN, "Unhandled data structure points to outside the buffer. ",
-                      "offset = ", dsOffset, ", length = ", dsSize,
-                      ", buffer length = ", tableStream.length);
+            LOGGER.atWarn().log("Unhandled data structure points to outside the buffer. offset = {}, length = {}, buffer length = {}", box(dsOffset),box(dsSize),box(tableStream.length));
           }
           else
           {
diff --git a/src/scratchpad/src/org/apache/poi/hwpf/model/FileInformationBlock.java b/src/scratchpad/src/org/apache/poi/hwpf/model/FileInformationBlock.java
index 879441b..fdb2205 100644
--- a/src/scratchpad/src/org/apache/poi/hwpf/model/FileInformationBlock.java
+++ b/src/scratchpad/src/org/apache/poi/hwpf/model/FileInformationBlock.java
@@ -24,14 +24,16 @@
 import java.util.HashSet;
 import java.util.Locale;
 
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.apache.poi.hwpf.model.types.FibBaseAbstractType;
 import org.apache.poi.hwpf.model.types.FibRgW97AbstractType;
 import org.apache.poi.util.IOUtils;
 import org.apache.poi.util.Internal;
 import org.apache.poi.util.LittleEndian;
 import org.apache.poi.util.LittleEndianConsts;
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
+
+import static org.apache.logging.log4j.util.Unbox.box;
 
 /**
  * <p>The File Information Block (FIB). Holds pointers
@@ -50,7 +52,7 @@
     //arbitrarily selected; may need to increase
     private static final int MAX_RECORD_LENGTH = 100_000;
 
-    private static final POILogger LOG = POILogFactory.getLogger( FileInformationBlock.class );
+    private static final Logger LOG = LogManager.getLogger(FileInformationBlock.class);
 
     private final FibBase _fibBase;
     private final int _csw;
@@ -175,7 +177,7 @@
             /* The Word spec has a much smaller list of "valid" values
              * to what the large CommonCrawl corpus contains!
              */
-            LOG.log(POILogger.WARN, "Invalid file format version number: ", nfib, "(", nfibHex, ")");
+            LOG.atWarn().log("Invalid file format version number: {}({})", box(nfib),nfibHex);
         }
     }
 
@@ -186,9 +188,7 @@
         if ( cbRgFcLcb == expectedCbRgFcLcb )
             return;
 
-        LOG.log( POILogger.WARN, "Since FIB.nFib == ", strNFib,
-                " value of FIB.cbRgFcLcb MUST be ", strCbRgFcLcb + ", not 0x",
-                Integer.toHexString( cbRgFcLcb ) );
+        LOG.atWarn().log("Since FIB.nFib == {} value of FIB.cbRgFcLcb MUST be {}, not 0x{}", strNFib, strCbRgFcLcb, Integer.toHexString(cbRgFcLcb));
     }
 
     private void assertCswNew()
@@ -211,7 +211,7 @@
             assertCswNew( "0x0112", 0x0005, "0x0005", _cswNew );
             break;
         default:
-            LOG.log(POILogger.WARN, "Invalid file format version number: ", getNFib());
+            LOG.atWarn().log("Invalid file format version number: {}", box(getNFib()));
         }
     }
 
@@ -222,9 +222,7 @@
         if ( cswNew == expectedCswNew )
             return;
 
-        LOG.log( POILogger.WARN, "Since FIB.nFib == ", strNFib,
-                " value of FIB.cswNew MUST be ",
-                strExpectedCswNew + ", not 0x", Integer.toHexString( cswNew ) );
+        LOG.atWarn().log("Since FIB.nFib == {} value of FIB.cswNew MUST be {}, not 0x{}", strNFib, strExpectedCswNew, Integer.toHexString(cswNew));
     }
 
     public void fillVariableFields( byte[] mainDocument, byte[] tableStream )
diff --git a/src/scratchpad/src/org/apache/poi/hwpf/model/FontTable.java b/src/scratchpad/src/org/apache/poi/hwpf/model/FontTable.java
index b5d28d1..8fba06f 100644
--- a/src/scratchpad/src/org/apache/poi/hwpf/model/FontTable.java
+++ b/src/scratchpad/src/org/apache/poi/hwpf/model/FontTable.java
@@ -20,12 +20,12 @@
 import java.io.ByteArrayOutputStream;
 import java.io.IOException;
 
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.apache.poi.hwpf.model.io.HWPFFileSystem;
 import org.apache.poi.util.Internal;
 import org.apache.poi.util.LittleEndian;
 import org.apache.poi.util.LittleEndianConsts;
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
 
 /**
  * FontTable or in MS terminology sttbfffn is a common data structure written in all
@@ -38,7 +38,7 @@
 @Internal
 public final class FontTable
 {
-    private static final POILogger LOG = POILogFactory.getLogger(FontTable.class);
+    private static final Logger LOG = LogManager.getLogger(FontTable.class);
     private short _stringCount;// how many strings are included in the string table
     private short _extraDataSz;// size in bytes of the extra data
 
@@ -93,7 +93,7 @@
     {
         if(chpFtc >= _stringCount)
         {
-            LOG.log(POILogger.INFO, "Mismatch in chpFtc with stringCount");
+            LOG.atInfo().log("Mismatch in chpFtc with stringCount");
             return null;
         }
 
@@ -104,7 +104,7 @@
     {
         if(chpFtc >= _stringCount)
         {
-            LOG.log(POILogger.INFO, "Mismatch in chpFtc with stringCount");
+            LOG.atInfo().log("Mismatch in chpFtc with stringCount");
             return null;
         }
 
diff --git a/src/scratchpad/src/org/apache/poi/hwpf/model/ListLevel.java b/src/scratchpad/src/org/apache/poi/hwpf/model/ListLevel.java
index 36b069d..f13e9a3 100644
--- a/src/scratchpad/src/org/apache/poi/hwpf/model/ListLevel.java
+++ b/src/scratchpad/src/org/apache/poi/hwpf/model/ListLevel.java
@@ -19,11 +19,13 @@
 
 import java.util.Arrays;
 
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.apache.poi.hwpf.model.types.LVLFAbstractType;
 import org.apache.poi.util.IOUtils;
 import org.apache.poi.util.Internal;
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
+
+import static org.apache.logging.log4j.util.Unbox.box;
 
 /**
  * "The LVL structure contains formatting information about a specific level in
@@ -43,7 +45,7 @@
     //arbitrarily selected; may need to increase
     private static final int MAX_RECORD_LENGTH = 10_485_760;
 
-    private static final POILogger LOG = POILogFactory.getLogger( ListLevel.class );
+    private static final Logger LOG = LogManager.getLogger(ListLevel.class);
 
     private byte[] _grpprlChpx;
     private byte[] _grpprlPapx;
@@ -244,10 +246,7 @@
         {
             if ( _xst.getCch() != 1 )
             {
-                LOG.log( POILogger.WARN, "LVL at offset ",
-                        Integer.valueOf( startOffset ),
-                        " has nfc == 0x17 (bullets), but cch != 1 (",
-                        Integer.valueOf( _xst.getCch() ), ")" );
+                LOG.atWarn().log("LVL at offset {} has nfc == 0x17 (bullets), but cch != 1 ({})", box(startOffset),box(_xst.getCch()));
             }
         }
 
diff --git a/src/scratchpad/src/org/apache/poi/hwpf/model/ListTables.java b/src/scratchpad/src/org/apache/poi/hwpf/model/ListTables.java
index b105fc1..e163b2f 100644
--- a/src/scratchpad/src/org/apache/poi/hwpf/model/ListTables.java
+++ b/src/scratchpad/src/org/apache/poi/hwpf/model/ListTables.java
@@ -23,17 +23,19 @@
 import java.util.NoSuchElementException;
 import java.util.Objects;
 
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.apache.poi.hwpf.model.types.LSTFAbstractType;
 import org.apache.poi.util.Internal;
 import org.apache.poi.util.LittleEndian;
 import org.apache.poi.util.LittleEndianConsts;
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
+
+import static org.apache.logging.log4j.util.Unbox.box;
 
 @Internal
 public final class ListTables
 {
-  private static final POILogger log = POILogFactory.getLogger(ListTables.class);
+  private static final Logger LOGGER = LogManager.getLogger(ListTables.class);
 
     /**
      * Both PlfLst and the following LVLs
@@ -141,13 +143,13 @@
   {
     ListData lst = _listMap.get(lsid);
     if (lst == null) {
-        log.log(POILogger.WARN, "ListData for ", lsid, " was null.");
+        LOGGER.atWarn().log("ListData for {} was null.", box(lsid));
         return null;
     }
     if(level < lst.numLevels()) {
         return lst.getLevels()[level];
     }
-    log.log(POILogger.WARN, "Requested level ", level, " which was greater than the maximum defined (", lst.numLevels(), ")");
+      LOGGER.atWarn().log("Requested level {} which was greater than the maximum defined ({})", box(level),box(lst.numLevels()));
 	return null;
   }
 
diff --git a/src/scratchpad/src/org/apache/poi/hwpf/model/NilPICFAndBinData.java b/src/scratchpad/src/org/apache/poi/hwpf/model/NilPICFAndBinData.java
index 4f49fe9..3377c8c 100644
--- a/src/scratchpad/src/org/apache/poi/hwpf/model/NilPICFAndBinData.java
+++ b/src/scratchpad/src/org/apache/poi/hwpf/model/NilPICFAndBinData.java
@@ -18,16 +18,18 @@
 
 import java.util.Arrays;
 
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.apache.poi.util.LittleEndian;
 import org.apache.poi.util.LittleEndianConsts;
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
+
+import static java.lang.Integer.toHexString;
+import static org.apache.logging.log4j.util.Unbox.box;
 
 public class NilPICFAndBinData
 {
 
-    private static final POILogger log = POILogFactory
-            .getLogger( NilPICFAndBinData.class );
+    private static final Logger LOGGER = LogManager.getLogger(NilPICFAndBinData.class);
 
     private byte[] _binData;
 
@@ -44,9 +46,7 @@
 
         if ( cbHeader != 0x44 )
         {
-            log.log(POILogger.WARN, "NilPICFAndBinData at offset ", offset,
-                    " cbHeader 0x", Integer.toHexString(cbHeader), " != 0x44"
-            );
+            LOGGER.atWarn().log("NilPICFAndBinData at offset {} cbHeader 0x{} != 0x44", box(offset), toHexString(cbHeader));
         }
 
         // skip the 62 ignored bytes
diff --git a/src/scratchpad/src/org/apache/poi/hwpf/model/OldFfn.java b/src/scratchpad/src/org/apache/poi/hwpf/model/OldFfn.java
index 27e5de7..38c0d53 100644
--- a/src/scratchpad/src/org/apache/poi/hwpf/model/OldFfn.java
+++ b/src/scratchpad/src/org/apache/poi/hwpf/model/OldFfn.java
@@ -19,20 +19,22 @@
 
 import java.nio.charset.Charset;
 
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.apache.poi.common.usermodel.fonts.FontCharset;
 import org.apache.poi.util.Internal;
 import org.apache.poi.util.LittleEndianConsts;
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
 import org.apache.poi.util.StringUtil;
 
+import static org.apache.logging.log4j.util.Unbox.box;
+
 /**
  * Word 6.0 Font information
  */
 @Internal
 public final class OldFfn {
 
-    private static final POILogger LOG = POILogFactory.getLogger(OldFfn.class);
+    private static final Logger LOG = LogManager.getLogger(OldFfn.class);
 
     private final byte _chs;// character set identifier
 
@@ -59,7 +61,7 @@
         short fontDescriptionLength = buf[offset];
         offset += 1;
         if (offset + fontDescriptionLength > fontTableEnd) {
-            LOG.log(POILogger.WARN, "Asked to read beyond font table end. Skipping font");
+            LOG.atWarn().log("Asked to read beyond font table end. Skipping font");
             return null;
         }
 
@@ -69,7 +71,7 @@
         Charset charset = null;
         FontCharset wmfCharset = FontCharset.valueOf(chs & 0xff);
         if (wmfCharset == null) {
-            LOG.log(POILogger.WARN, "Couldn't find font for type: ", (chs & 0xff));
+            LOG.atWarn().log("Couldn't find font for type: {}", box((chs & 0xff)));
         } else {
             charset = wmfCharset.getCharset();
         }
@@ -88,7 +90,7 @@
             }
         }
         if (fontNameLength == -1) {
-            LOG.log(POILogger.WARN, "Couldn't find the zero-byte delimited font name length");
+            LOG.atWarn().log("Couldn't find the zero-byte delimited font name length");
             return null;
         }
         String fontName = new String(buf, offset, fontNameLength, charset);
diff --git a/src/scratchpad/src/org/apache/poi/hwpf/model/OldFontTable.java b/src/scratchpad/src/org/apache/poi/hwpf/model/OldFontTable.java
index 0e3ec37..d4935a1 100644
--- a/src/scratchpad/src/org/apache/poi/hwpf/model/OldFontTable.java
+++ b/src/scratchpad/src/org/apache/poi/hwpf/model/OldFontTable.java
@@ -21,18 +21,18 @@
 import java.util.Arrays;
 import java.util.List;
 
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.apache.poi.util.Internal;
 import org.apache.poi.util.LittleEndian;
 import org.apache.poi.util.LittleEndianConsts;
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
 
 /**
  * Font table for Word 6.0
  */
 @Internal
 public final class OldFontTable {
-    private static final POILogger LOG = POILogFactory.getLogger(OldFontTable.class);
+    private static final Logger LOG = LogManager.getLogger(OldFontTable.class);
 
     // added extra facilitator members
     // FFN structure containing strings of font names
@@ -69,7 +69,7 @@
 
     public String getMainFont(int chpFtc) {
         if (chpFtc >= _fontNames.length) {
-            LOG.log(POILogger.INFO, "Mismatch in chpFtc with stringCount");
+            LOG.atInfo().log("Mismatch in chpFtc with stringCount");
             return null;
         }
 
diff --git a/src/scratchpad/src/org/apache/poi/hwpf/model/PAPBinTable.java b/src/scratchpad/src/org/apache/poi/hwpf/model/PAPBinTable.java
index 25dae0d..675b62e 100644
--- a/src/scratchpad/src/org/apache/poi/hwpf/model/PAPBinTable.java
+++ b/src/scratchpad/src/org/apache/poi/hwpf/model/PAPBinTable.java
@@ -26,14 +26,17 @@
 import java.util.List;
 import java.util.Map;
 
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.apache.poi.hwpf.sprm.SprmBuffer;
 import org.apache.poi.hwpf.sprm.SprmIterator;
 import org.apache.poi.hwpf.sprm.SprmOperation;
 import org.apache.poi.poifs.common.POIFSConstants;
 import org.apache.poi.util.Internal;
 import org.apache.poi.util.LittleEndian;
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
+
+import static java.lang.System.currentTimeMillis;
+import static org.apache.logging.log4j.util.Unbox.box;
 
 /**
  * This class represents the bin table of Word document but it also serves as a
@@ -43,7 +46,7 @@
 @Internal
 public class PAPBinTable
 {
-    private static final POILogger LOG = POILogFactory.getLogger( PAPBinTable.class );
+    private static final Logger LOG = LogManager.getLogger(PAPBinTable.class);
 
     protected final ArrayList<PAPX> _paragraphs = new ArrayList<>();
 
@@ -55,7 +58,7 @@
             byte[] dataStream, int offset, int size,
             CharIndexTranslator charIndexTranslator )
     {
-        long start = System.currentTimeMillis();
+        long start = currentTimeMillis();
 
         {
             PlexOfCps binTable = new PlexOfCps( tableStream, offset, size, 4 );
@@ -80,13 +83,11 @@
             }
         }
 
-        LOG.log( POILogger.DEBUG, "PAPX tables loaded in ",
-                Long.valueOf( System.currentTimeMillis() - start ), " ms (",
-                Integer.valueOf( _paragraphs.size() ), " elements)" );
+        LOG.atDebug().log("PAPX tables loaded in {} ms ({} elements)", box(currentTimeMillis() - start),box(_paragraphs.size()));
 
         if ( _paragraphs.isEmpty() )
         {
-            LOG.log( POILogger.WARN, "PAPX FKPs are empty" );
+            LOG.atWarn().log("PAPX FKPs are empty");
             _paragraphs.add( new PAPX( 0, 0, new SprmBuffer( 2 ) ) );
         }
     }
@@ -100,7 +101,7 @@
     static void rebuild( final StringBuilder docText,
             ComplexFileTable complexFileTable, List<PAPX> paragraphs )
     {
-        long start = System.currentTimeMillis();
+        long start = currentTimeMillis();
 
         if ( complexFileTable != null )
         {
@@ -117,8 +118,7 @@
 
                 if ( igrpprl < 0 || igrpprl >= sprmBuffers.length )
                 {
-                    LOG.log( POILogger.WARN, textPiece
-                            + "'s PRM references to unknown grpprl" );
+                    LOG.atWarn().log("{}'s PRM references to unknown grpprl", textPiece);
                     continue;
                 }
 
@@ -146,20 +146,15 @@
                 }
             }
 
-            LOG.log( POILogger.DEBUG,
-                    "Merged (?) with PAPX from complex file table in ",
-                    Long.valueOf( System.currentTimeMillis() - start ),
-                    " ms (", Integer.valueOf( paragraphs.size() ),
-                    " elements in total)" );
-            start = System.currentTimeMillis();
+            LOG.atDebug().log("Merged (?) with PAPX from complex file table in {} ms ({} elements in total)", box(currentTimeMillis() - start),box(paragraphs.size()));
+            start = currentTimeMillis();
         }
 
         List<PAPX> oldPapxSortedByEndPos = new ArrayList<>(paragraphs);
         oldPapxSortedByEndPos.sort(PropertyNode.EndComparator);
 
-        LOG.log( POILogger.DEBUG, "PAPX sorted by end position in ",
-                Long.valueOf( System.currentTimeMillis() - start ), " ms" );
-        start = System.currentTimeMillis();
+        LOG.atDebug().log("PAPX sorted by end position in {} ms", box(currentTimeMillis() - start));
+        start = currentTimeMillis();
 
         final Map<PAPX, Integer> papxToFileOrder = new IdentityHashMap<>();
         {
@@ -179,9 +174,8 @@
             }
         };
 
-        LOG.log( POILogger.DEBUG, "PAPX's order map created in ",
-                Long.valueOf( System.currentTimeMillis() - start ), " ms" );
-        start = System.currentTimeMillis();
+        LOG.atDebug().log("PAPX's order map created in {} ms", box(currentTimeMillis() - start));
+        start = currentTimeMillis();
 
         List<PAPX> newPapxs = new LinkedList<>();
         int lastParStart = 0;
@@ -223,10 +217,7 @@
 
             if ( papxs.size() == 0 )
             {
-                LOG.log( POILogger.WARN, "Paragraph [",
-                        Integer.valueOf( startInclusive ), "; ",
-                        Integer.valueOf( endExclusive ),
-                        ") has no PAPX. Creating new one." );
+                LOG.atWarn().log("Paragraph [{}; {}) has no PAPX. Creating new one.", box(startInclusive),box(endExclusive));
                 // create it manually
                 PAPX papx = new PAPX( startInclusive, endExclusive,
                         new SprmBuffer( 2 ) );
@@ -273,9 +264,7 @@
         paragraphs.clear();
         paragraphs.addAll( newPapxs );
 
-        LOG.log( POILogger.DEBUG, "PAPX rebuilded from document text in ",
-                Long.valueOf( System.currentTimeMillis() - start ), " ms (",
-                Integer.valueOf( paragraphs.size() ), " elements)" );
+        LOG.atDebug().log("PAPX rebuilded from document text in {} ms ({} elements)", box(currentTimeMillis() - start),box(paragraphs.size()));
     }
 
     public void insert(int listIndex, int cpStart, SprmBuffer buf)
diff --git a/src/scratchpad/src/org/apache/poi/hwpf/model/PicturesTable.java b/src/scratchpad/src/org/apache/poi/hwpf/model/PicturesTable.java
index bf904e4..c5e8e0d 100644
--- a/src/scratchpad/src/org/apache/poi/hwpf/model/PicturesTable.java
+++ b/src/scratchpad/src/org/apache/poi/hwpf/model/PicturesTable.java
@@ -17,9 +17,12 @@
 
 package org.apache.poi.hwpf.model;
 
+import java.io.OutputStream;
 import java.util.ArrayList;
 import java.util.List;
 
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.apache.poi.ddf.DefaultEscherRecordFactory;
 import org.apache.poi.ddf.EscherBSERecord;
 import org.apache.poi.ddf.EscherBlipRecord;
@@ -31,8 +34,8 @@
 import org.apache.poi.hwpf.usermodel.Range;
 import org.apache.poi.util.Internal;
 import org.apache.poi.util.LittleEndian;
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
+
+import static org.apache.logging.log4j.util.Unbox.box;
 
 /**
  * Holds information about all pictures embedded in Word Document either via "Insert -> Picture -> From File" or via
@@ -53,9 +56,9 @@
  */
 @Internal
 public final class PicturesTable {
-    private static final POILogger LOG = POILogFactory.getLogger( PicturesTable.class );
+    private static final Logger LOG = LogManager.getLogger(PicturesTable.class);
 
-  static final int TYPE_IMAGE = 0x08;
+    static final int TYPE_IMAGE = 0x08;
   static final int TYPE_IMAGE_WORD2000 = 0x00;
   static final int TYPE_IMAGE_PASTED_FROM_CLIPBOARD = 0xA;
   static final int TYPE_IMAGE_PASTED_FROM_CLIPBOARD_WORD2000 = 0x2;
@@ -151,9 +154,9 @@
    * @param run
    * @param fillBytes if true, Picture will be returned with filled byte array that represent picture's contents. If you don't want
    * to have that byte array in memory but only write picture's contents to stream, pass false and then use Picture.writeImageContent
-   * @see Picture#writeImageContent(java.io.OutputStream)
+   * @see Picture#writeImageContent(OutputStream)
    * @return a Picture object if picture exists for specified CharacterRun, null otherwise. PicturesTable.hasPicture is used to determine this.
-   * @see #hasPicture(org.apache.poi.hwpf.usermodel.CharacterRun)
+   * @see #hasPicture(CharacterRun)
    */
   public Picture extractPicture(CharacterRun run, boolean fillBytes) {
     if (hasPicture(run)) {
@@ -198,10 +201,7 @@
                     }
                     catch ( Exception exc )
                     {
-                        LOG.log(
-                                POILogger.WARN,
-                                "Unable to load picture from BLIB record at offset #",
-                                Integer.valueOf( bse.getOffset() ), exc );
+                        LOG.atWarn().withThrowable(exc).log("Unable to load picture from BLIP record at offset #{}", box(bse.getOffset()));
                     }
                 }
           }
diff --git a/src/scratchpad/src/org/apache/poi/hwpf/model/PlfLfo.java b/src/scratchpad/src/org/apache/poi/hwpf/model/PlfLfo.java
index dbe3246..b2adc51 100644
--- a/src/scratchpad/src/org/apache/poi/hwpf/model/PlfLfo.java
+++ b/src/scratchpad/src/org/apache/poi/hwpf/model/PlfLfo.java
@@ -23,11 +23,13 @@
 import java.util.Arrays;
 import java.util.NoSuchElementException;
 
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.apache.poi.hwpf.model.types.LFOAbstractType;
 import org.apache.poi.util.LittleEndian;
 import org.apache.poi.util.LittleEndianConsts;
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
+
+import static org.apache.logging.log4j.util.Unbox.box;
 
 /**
  * The PlfLfo structure contains the list format override data for the document.
@@ -39,7 +41,7 @@
  */
 public class PlfLfo
 {
-    private static final POILogger log = POILogFactory.getLogger( PlfLfo.class );
+    private static final Logger LOGGER = LogManager.getLogger(PlfLfo.class);
 
     /**
      * An unsigned integer that specifies the count of elements in both the
@@ -107,11 +109,7 @@
 
         if ( ( offset - fcPlfLfo ) != lcbPlfLfo )
         {
-            if (log.check(POILogger.WARN)) {
-                log.log(POILogger.WARN, "Actual size of PlfLfo is "
-                        + (offset - fcPlfLfo) + " bytes, but expected "
-                        + lcbPlfLfo);
-            }
+            LOGGER.atWarn().log("Actual size of PlfLfo is {} bytes, but expected {}", box(offset - fcPlfLfo),box(lcbPlfLfo));
         }
     }
 
diff --git a/src/scratchpad/src/org/apache/poi/hwpf/model/PropertyNode.java b/src/scratchpad/src/org/apache/poi/hwpf/model/PropertyNode.java
index 4746799..7784e41 100644
--- a/src/scratchpad/src/org/apache/poi/hwpf/model/PropertyNode.java
+++ b/src/scratchpad/src/org/apache/poi/hwpf/model/PropertyNode.java
@@ -21,10 +21,12 @@
 import java.util.Comparator;
 import java.util.Objects;
 
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.apache.poi.common.Duplicatable;
 import org.apache.poi.util.Internal;
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
+
+import static org.apache.logging.log4j.util.Unbox.box;
 
 /**
  * Represents a lightweight node in the Trees used to store content
@@ -40,7 +42,7 @@
 
     public static final Comparator<PropertyNode<?>> StartComparator = Comparator.comparingInt(PropertyNode::getStart);
 
-    private static final POILogger LOG = POILogFactory.getLogger(PropertyNode.class);
+    private static final Logger LOG = LogManager.getLogger(PropertyNode.class);
 
 
     protected Object _buf;
@@ -72,13 +74,12 @@
         _buf = buf;
 
         if (_cpStart < 0) {
-            LOG.log(POILogger.WARN, "A property claimed to start before zero, at ", _cpStart, "! Resetting it to zero, and hoping for the best");
+            LOG.atWarn().log("A property claimed to start before zero, at {}! Resetting it to zero, and hoping for the best", box(_cpStart));
             _cpStart = 0;
         }
 
         if (_cpEnd < _cpStart) {
-            LOG.log(POILogger.WARN, "A property claimed to end (", _cpEnd,
-                    ") before start! Resetting end to start, and hoping for the best");
+            LOG.atWarn().log("A property claimed to end ({}) before start! Resetting end to start, and hoping for the best", box(_cpEnd));
             _cpEnd = _cpStart;
         }
     }
diff --git a/src/scratchpad/src/org/apache/poi/hwpf/model/SectionTable.java b/src/scratchpad/src/org/apache/poi/hwpf/model/SectionTable.java
index 4656ec8..547960c 100644
--- a/src/scratchpad/src/org/apache/poi/hwpf/model/SectionTable.java
+++ b/src/scratchpad/src/org/apache/poi/hwpf/model/SectionTable.java
@@ -22,13 +22,13 @@
 import java.util.ArrayList;
 import java.util.List;
 
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.apache.poi.hwpf.model.io.HWPFFileSystem;
 import org.apache.poi.util.IOUtils;
 import org.apache.poi.util.Internal;
 import org.apache.poi.util.LittleEndian;
 import org.apache.poi.util.LittleEndianConsts;
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
 
 @Internal
 public class SectionTable
@@ -37,7 +37,7 @@
     //arbitrarily selected; may need to increase
     private static final int MAX_RECORD_LENGTH = 100_000;
 
-    private static final POILogger LOG = POILogFactory.getLogger(SectionTable.class);
+    private static final Logger LOG = LogManager.getLogger(SectionTable.class);
     private static final int SED_SIZE = 12;
 
     protected List<SEPX> _sections = new ArrayList<>();
@@ -100,7 +100,7 @@
             }
         }
         if(! matchAt && matchHalf) {
-            LOG.log(POILogger.WARN, "Your document seemed to be mostly unicode, but the section definition was in bytes! Trying anyway, but things may well go wrong!");
+            LOG.atWarn().log("Your document seemed to be mostly unicode, but the section definition was in bytes! Trying anyway, but things may well go wrong!");
             for(int i=0; i<_sections.size(); i++) {
                 SEPX s = _sections.get(i);
                 GenericPropertyNode node = sedPlex.getProperty(i);
diff --git a/src/scratchpad/src/org/apache/poi/hwpf/model/Sttb.java b/src/scratchpad/src/org/apache/poi/hwpf/model/Sttb.java
index 385650b..85343ee 100644
--- a/src/scratchpad/src/org/apache/poi/hwpf/model/Sttb.java
+++ b/src/scratchpad/src/org/apache/poi/hwpf/model/Sttb.java
@@ -18,10 +18,9 @@
 
 import java.util.Arrays;
 
+import org.apache.logging.log4j.LogManager;
 import org.apache.poi.util.LittleEndian;
 import org.apache.poi.util.LittleEndianConsts;
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
 import org.apache.poi.util.StringUtil;
 
 /**
@@ -81,11 +80,11 @@
 
         if ( ffff != (short) 0xffff )
         {
-            POILogFactory.getLogger(Sttb.class).log(
-                    POILogger.WARN,
-                    "Non-extended character Pascal strings are not supported right now. ",
-                    "Creating empty values in the RevisionMarkAuthorTable for now.  ",
-                    "Please, contact POI developers for update.");
+            LogManager.getLogger(Sttb.class).atWarn().log(
+                    "Non-extended character Pascal strings are not supported right now. " +
+                            "Creating empty values in the RevisionMarkAuthorTable for now.  " +
+                            "Please, contact POI developers for update."
+            );
             //set data and extraData to empty values to avoid
             //downstream NPE in case someone calls getEntries on RevisionMarkAuthorTable
             _data = new String[0];
diff --git a/src/scratchpad/src/org/apache/poi/hwpf/model/StyleDescription.java b/src/scratchpad/src/org/apache/poi/hwpf/model/StyleDescription.java
index 7dcc6e5..05b2c04 100644
--- a/src/scratchpad/src/org/apache/poi/hwpf/model/StyleDescription.java
+++ b/src/scratchpad/src/org/apache/poi/hwpf/model/StyleDescription.java
@@ -20,6 +20,8 @@
 import java.util.Arrays;
 import java.util.Objects;
 
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.apache.poi.hwpf.model.types.StdfBaseAbstractType;
 import org.apache.poi.hwpf.usermodel.CharacterProperties;
 import org.apache.poi.hwpf.usermodel.ParagraphProperties;
@@ -27,10 +29,10 @@
 import org.apache.poi.util.Internal;
 import org.apache.poi.util.LittleEndian;
 import org.apache.poi.util.LittleEndianConsts;
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
 import org.apache.poi.util.StringUtil;
 
+import static org.apache.logging.log4j.util.Unbox.box;
+
 /**
  * Comment me
  *
@@ -39,7 +41,7 @@
 @Internal
 public final class StyleDescription {
 
-    private static final POILogger LOG = POILogFactory.getLogger(StyleDescription.class);
+    private static final Logger LOG = LogManager.getLogger(StyleDescription.class);
     //arbitrarily selected; may need to increase
     private static final int MAX_RECORD_LENGTH = 100_000;
 
@@ -74,7 +76,7 @@
         } else if (baseLength == 0x000A) {
             readStdfPost2000 = false;
         } else {
-            LOG.log(POILogger.WARN, "Style definition has non-standard size of ", baseLength);
+            LOG.atWarn().log("Style definition has non-standard size of {}", box(baseLength));
         }
 
         _stdfBase = new StdfBase(std, offset);
diff --git a/src/scratchpad/src/org/apache/poi/hwpf/model/TextPieceTable.java b/src/scratchpad/src/org/apache/poi/hwpf/model/TextPieceTable.java
index e40be66..cd885b9 100644
--- a/src/scratchpad/src/org/apache/poi/hwpf/model/TextPieceTable.java
+++ b/src/scratchpad/src/org/apache/poi/hwpf/model/TextPieceTable.java
@@ -25,11 +25,14 @@
 import java.util.LinkedList;
 import java.util.List;
 
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.apache.poi.poifs.common.POIFSConstants;
 import org.apache.poi.util.IOUtils;
 import org.apache.poi.util.Internal;
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
+
+import static java.lang.System.currentTimeMillis;
+import static org.apache.logging.log4j.util.Unbox.box;
 
 /**
  * The piece table for matching up character positions to bits of text. This
@@ -40,7 +43,7 @@
  */
 @Internal
 public class TextPieceTable implements CharIndexTranslator {
-    private static final POILogger LOG = POILogFactory.getLogger(TextPieceTable.class);
+    private static final Logger LOG = LogManager.getLogger(TextPieceTable.class);
     //arbitrarily selected; may need to increase
     private static final int MAX_RECORD_LENGTH = 100_000_000;
 
@@ -277,7 +280,7 @@
     }
 
     public StringBuilder getText() {
-        final long start = System.currentTimeMillis();
+        final long start = currentTimeMillis();
 
         // rebuild document paragraphs structure
         StringBuilder docText = new StringBuilder();
@@ -286,23 +289,14 @@
             int toAppendLength = toAppend.length();
 
             if (toAppendLength != textPiece.getEnd() - textPiece.getStart()) {
-                LOG.log(
-                        POILogger.WARN,
-                        "Text piece has boundaries [",
-                        textPiece.getStart(),
-                        "; ",
-                        textPiece.getEnd(),
-                        ") but length ",
-                        textPiece.getEnd() - textPiece.getStart());
+                LOG.atWarn().log("Text piece has boundaries [{}; {}) but length {}", box(textPiece.getStart()),box(textPiece.getEnd()),box(textPiece.getEnd() - textPiece.getStart()));
             }
 
             docText.replace(textPiece.getStart(), textPiece.getStart()
                     + toAppendLength, toAppend);
         }
 
-        LOG.log(POILogger.DEBUG, "Document text were rebuilded in ",
-                System.currentTimeMillis() - start, " ms (",
-                docText.length(), " chars)");
+        LOG.atDebug().log("Document text were rebuilt in {} ms ({} chars)", box(currentTimeMillis() - start),box(docText.length()));
 
         return docText;
     }
diff --git a/src/scratchpad/src/org/apache/poi/hwpf/model/Xstz.java b/src/scratchpad/src/org/apache/poi/hwpf/model/Xstz.java
index 242fb67..34acfb9 100644
--- a/src/scratchpad/src/org/apache/poi/hwpf/model/Xstz.java
+++ b/src/scratchpad/src/org/apache/poi/hwpf/model/Xstz.java
@@ -16,16 +16,18 @@
 ==================================================================== */
 package org.apache.poi.hwpf.model;
 
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.apache.poi.util.Internal;
 import org.apache.poi.util.LittleEndian;
 import org.apache.poi.util.LittleEndianConsts;
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
+
+import static org.apache.logging.log4j.util.Unbox.box;
 
 @Internal
 public class Xstz
 {
-    private static final POILogger log = POILogFactory.getLogger( Xstz.class );
+    private static final Logger LOGGER = LogManager.getLogger(Xstz.class);
 
     private final short _chTerm = 0;
     private Xst _xst;
@@ -50,10 +52,7 @@
         short term = LittleEndian.getShort( data, offset );
         if ( term != 0 )
         {
-            if (log.check(POILogger.WARN)) {
-                log.log(POILogger.WARN, "chTerm at the end of Xstz at offset ",
-                        offset, " is not 0");
-            }
+            LOGGER.atWarn().log("chTerm at the end of Xstz at offset {} is not 0", box(offset));
         }
     }
 
diff --git a/src/scratchpad/src/org/apache/poi/hwpf/sprm/CharacterSprmUncompressor.java b/src/scratchpad/src/org/apache/poi/hwpf/sprm/CharacterSprmUncompressor.java
index 27ad6e8..bad4429 100644
--- a/src/scratchpad/src/org/apache/poi/hwpf/sprm/CharacterSprmUncompressor.java
+++ b/src/scratchpad/src/org/apache/poi/hwpf/sprm/CharacterSprmUncompressor.java
@@ -17,6 +17,8 @@
 
 package org.apache.poi.hwpf.sprm;
 
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.apache.poi.hwpf.usermodel.ShadingDescriptor80;
 
 import org.apache.poi.hwpf.model.Colorref;
@@ -28,15 +30,13 @@
 import org.apache.poi.hwpf.usermodel.ShadingDescriptor;
 import org.apache.poi.util.Internal;
 import org.apache.poi.util.LittleEndian;
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
 
 @Internal
 public final class CharacterSprmUncompressor extends SprmUncompressor
 {
-    private static final POILogger LOG = POILogFactory.getLogger( CharacterSprmUncompressor.class );
+    private static final Logger LOG = LogManager.getLogger(CharacterSprmUncompressor.class);
 
-  public CharacterSprmUncompressor()
+    public CharacterSprmUncompressor()
   {
   }
 
@@ -77,8 +77,7 @@
             }
             catch ( Exception exc )
             {
-                LOG.log( POILogger.ERROR, "Unable to apply all style ",
-                        style, " CHP SPRMs to CHP: ", exc, exc );
+                LOG.atError().withThrowable(exc).log("Unable to apply all style {} CHP SPRMs to CHP", style);
             }
         }
 
@@ -91,8 +90,7 @@
         }
         catch ( Exception exc )
         {
-            LOG.log( POILogger.ERROR,
-                    "Unable to process all direct CHP SPRMs: ", exc, exc );
+            LOG.atError().withThrowable(exc).log("Unable to process all direct CHP SPRMs");
         }
         return newProperties;
     }
@@ -111,8 +109,7 @@
             {
                 if ( warnAboutNonChpSprms )
                 {
-                    LOG.log( POILogger.WARN,
-                            "Non-CHP SPRM returned by SprmIterator: ", sprm );
+                    LOG.atWarn().log("Non-CHP SPRM returned by SprmIterator: {}", sprm);
                 }
                 continue;
             }
@@ -140,8 +137,7 @@
         }
         catch ( Exception exc )
         {
-            LOG.log( POILogger.ERROR,
-                    "Unable to extract istd from direct CHP SPRM: ", exc, exc );
+            LOG.atError().withThrowable(exc).log("Unable to extract istd from direct CHP SPRM");
         }
         return style;
     }
@@ -705,7 +701,7 @@
 					oldCHP.isFNoProof()));
 			break;
       default:
-          LOG.log( POILogger.DEBUG, "Unknown CHP sprm ignored: ", sprm );
+          LOG.atDebug().log("Unknown CHP sprm ignored: {}", sprm);
           break;
     }
   }
diff --git a/src/scratchpad/src/org/apache/poi/hwpf/sprm/ParagraphSprmUncompressor.java b/src/scratchpad/src/org/apache/poi/hwpf/sprm/ParagraphSprmUncompressor.java
index fc3915d..d1d4191 100644
--- a/src/scratchpad/src/org/apache/poi/hwpf/sprm/ParagraphSprmUncompressor.java
+++ b/src/scratchpad/src/org/apache/poi/hwpf/sprm/ParagraphSprmUncompressor.java
@@ -24,6 +24,8 @@
 import java.util.List;
 import java.util.Map;
 
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.apache.poi.hwpf.model.TabDescriptor;
 import org.apache.poi.hwpf.model.types.TBDAbstractType;
 import org.apache.poi.hwpf.usermodel.BorderCode;
@@ -36,13 +38,13 @@
 import org.apache.poi.util.Internal;
 import org.apache.poi.util.LittleEndian;
 import org.apache.poi.util.LittleEndianConsts;
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
+
+import static org.apache.logging.log4j.util.Unbox.box;
 
 @Internal
 public final class ParagraphSprmUncompressor extends SprmUncompressor {
 
-    private static final POILogger LOG = POILogFactory.getLogger( ParagraphSprmUncompressor.class );
+    private static final Logger LOG = LogManager.getLogger(ParagraphSprmUncompressor.class);
 
   public ParagraphSprmUncompressor()
   {
@@ -69,9 +71,7 @@
           }
           catch ( Exception exc )
           {
-              LOG.log(
-                      POILogger.ERROR,
-                      "Unable to apply SPRM operation '", sprm.getOperation(), "': ", exc );
+            LOG.atError().withThrowable(exc).log("Unable to apply SPRM operation '{}'", box(sprm.getOperation()));
           }
       }
     }
@@ -411,7 +411,7 @@
           newPAP.setRsid( sprm.getOperand() );
           break;
         default:
-            LOG.log( POILogger.DEBUG, "Unknown PAP sprm ignored: ", sprm );
+            LOG.atDebug().log("Unknown PAP sprm ignored: {}", sprm);
             break;
         }
   }
diff --git a/src/scratchpad/src/org/apache/poi/hwpf/sprm/SectionSprmUncompressor.java b/src/scratchpad/src/org/apache/poi/hwpf/sprm/SectionSprmUncompressor.java
index a51f7c7..68375bb 100644
--- a/src/scratchpad/src/org/apache/poi/hwpf/sprm/SectionSprmUncompressor.java
+++ b/src/scratchpad/src/org/apache/poi/hwpf/sprm/SectionSprmUncompressor.java
@@ -19,18 +19,20 @@
 
 import java.util.Arrays;
 
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.apache.poi.hwpf.usermodel.BorderCode;
 import org.apache.poi.hwpf.usermodel.SectionProperties;
-import org.apache.poi.util.HexDump;
 import org.apache.poi.util.Internal;
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
+
+import static org.apache.logging.log4j.util.Unbox.box;
+import static org.apache.poi.util.HexDump.byteToHex;
 
 
 @Internal
 public final class SectionSprmUncompressor extends SprmUncompressor {
 
-  private static final POILogger LOG = POILogFactory.getLogger(SectionSprmUncompressor.class);
+  private static final Logger LOG = LogManager.getLogger(SectionSprmUncompressor.class);
 
   public SectionSprmUncompressor()
   {
@@ -241,7 +243,7 @@
         newSEP.setNfcEdnRef(sprm.getOperand());
         break;
       default:
-        LOG.log(POILogger.INFO, "Unsupported Sprm operation: ", operation, " (", HexDump.byteToHex(operation), ")");
+        LOG.atInfo().log("Unsupported Sprm operation: {} ({})", box(operation), byteToHex(operation));
         break;
     }
 
diff --git a/src/scratchpad/src/org/apache/poi/hwpf/sprm/TableSprmUncompressor.java b/src/scratchpad/src/org/apache/poi/hwpf/sprm/TableSprmUncompressor.java
index 0332ae3..9feb505 100644
--- a/src/scratchpad/src/org/apache/poi/hwpf/sprm/TableSprmUncompressor.java
+++ b/src/scratchpad/src/org/apache/poi/hwpf/sprm/TableSprmUncompressor.java
@@ -17,18 +17,18 @@
 
 package org.apache.poi.hwpf.sprm;
 
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.apache.poi.hwpf.usermodel.BorderCode;
 import org.apache.poi.hwpf.usermodel.TableCellDescriptor;
 import org.apache.poi.hwpf.usermodel.TableProperties;
 import org.apache.poi.util.Internal;
 import org.apache.poi.util.LittleEndian;
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
 
 @Internal
 public final class TableSprmUncompressor extends SprmUncompressor {
 
-  private static final POILogger LOG = POILogFactory.getLogger( TableSprmUncompressor.class );
+  private static final Logger LOG = LogManager.getLogger(TableSprmUncompressor.class);
 
   public TableSprmUncompressor()
   {
@@ -48,8 +48,7 @@
         }
         else
         {
-            LOG.log( POILogger.WARN,
-                    "Some table rows didn't specify number of columns in SPRMs" );
+            LOG.atWarn().log("Some table rows didn't specify number of columns in SPRMs");
             tableProperties = new TableProperties( (short) 1 );
         }
 
@@ -69,8 +68,7 @@
                 }
                 catch ( ArrayIndexOutOfBoundsException ex )
                 {
-                    LOG.log( POILogger.ERROR, "Unable to apply ", sprm,
-                            ": ", ex, ex );
+                  LOG.atError().withThrowable(ex).log("Unable to apply {}", sprm);
                 }
             }
         }
diff --git a/src/scratchpad/src/org/apache/poi/hwpf/usermodel/Paragraph.java b/src/scratchpad/src/org/apache/poi/hwpf/usermodel/Paragraph.java
index 27389f4..e5d1395 100644
--- a/src/scratchpad/src/org/apache/poi/hwpf/usermodel/Paragraph.java
+++ b/src/scratchpad/src/org/apache/poi/hwpf/usermodel/Paragraph.java
@@ -19,6 +19,8 @@
 
 import java.util.NoSuchElementException;
 
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.apache.poi.common.Duplicatable;
 import org.apache.poi.hwpf.HWPFDocumentCore;
 import org.apache.poi.hwpf.model.LFO;
@@ -30,11 +32,11 @@
 import org.apache.poi.hwpf.sprm.SprmBuffer;
 import org.apache.poi.hwpf.sprm.TableSprmCompressor;
 import org.apache.poi.util.Internal;
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
+
+import static org.apache.logging.log4j.util.Unbox.box;
 
 public class Paragraph extends Range implements Duplicatable {
-    private static final POILogger log = POILogFactory.getLogger( Paragraph.class );
+    private static final Logger LOGGER = LogManager.getLogger(Paragraph.class);
 
     public static final short SPRM_JC = 0x2403;
     public static final short SPRM_FSIDEBYSIDE = 0x2404;
@@ -118,8 +120,7 @@
             }
             catch ( NoSuchElementException exc )
             {
-                log.log( POILogger.WARN, "Paragraph refers to LFO #",
-                        properties.getIlfo(), " that does not exists" );
+                LOGGER.atWarn().log("Paragraph refers to LFO #{} that does not exists", box(properties.getIlfo()));
             }
             if ( lfo != null )
             {
diff --git a/src/scratchpad/src/org/apache/poi/hwpf/usermodel/Picture.java b/src/scratchpad/src/org/apache/poi/hwpf/usermodel/Picture.java
index c91a38f..315e0be 100644
--- a/src/scratchpad/src/org/apache/poi/hwpf/usermodel/Picture.java
+++ b/src/scratchpad/src/org/apache/poi/hwpf/usermodel/Picture.java
@@ -25,6 +25,8 @@
 import java.util.List;
 import java.util.zip.InflaterInputStream;
 
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.apache.poi.ddf.EscherBSERecord;
 import org.apache.poi.ddf.EscherBlipRecord;
 import org.apache.poi.ddf.EscherComplexProperty;
@@ -35,16 +37,13 @@
 import org.apache.poi.hwpf.model.PICF;
 import org.apache.poi.hwpf.model.PICFAndOfficeArtData;
 import org.apache.poi.sl.image.ImageHeaderPNG;
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
 import org.apache.poi.util.StringUtil;
 
 /**
  * Represents embedded picture extracted from Word Document
  */
 public final class Picture {
-    private static final POILogger log = POILogFactory
-            .getLogger( Picture.class );
+    private static final Logger LOGGER = LogManager.getLogger(Picture.class);
 
     private static final byte[] COMPRESSED1 = { (byte) 0xFE, 0x78, (byte) 0xDA };
 
@@ -161,9 +160,7 @@
                  * Problems reading from the actual ByteArrayInputStream should
                  * never happen so this will only ever be a ZipException.
                  */
-                log.log( POILogger.INFO,
-                        "Possibly corrupt compression or non-compressed data",
-                        e );
+                LOGGER.atInfo().withThrowable(e).log("Possibly corrupt compression or non-compressed data");
             }
         }
         else
diff --git a/src/scratchpad/src/org/apache/poi/hwpf/usermodel/Range.java b/src/scratchpad/src/org/apache/poi/hwpf/usermodel/Range.java
index 7351723..0b6cbcb 100644
--- a/src/scratchpad/src/org/apache/poi/hwpf/usermodel/Range.java
+++ b/src/scratchpad/src/org/apache/poi/hwpf/usermodel/Range.java
@@ -18,9 +18,12 @@
 package org.apache.poi.hwpf.usermodel;
 
 import static java.util.stream.Collectors.toList;
+import static org.apache.logging.log4j.util.Unbox.box;
 
 import java.util.List;
 
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.apache.poi.hwpf.HWPFDocument;
 import org.apache.poi.hwpf.HWPFDocumentCore;
 import org.apache.poi.hwpf.model.CHPX;
@@ -37,8 +40,6 @@
 import org.apache.poi.util.Internal;
 import org.apache.poi.util.LittleEndian;
 import org.apache.poi.util.LittleEndianConsts;
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
 
 /**
  * This class is the central class of the HWPF object model. All properties that
@@ -53,9 +54,9 @@
  */
 public class Range {
 
-    private static final POILogger LOG = POILogFactory.getLogger( Range.class );
+    private static final Logger LOG = LogManager.getLogger(Range.class);
 
-    /**
+	/**
      * @deprecated POI 3.8 beta 5
      */
     @Deprecated
@@ -824,10 +825,8 @@
         initAll();
         if ( tableEndInclusive >= this._parEnd )
         {
-            LOG.log( POILogger.WARN, "The table's bounds ", "[",
-                    this._parStart, "; ", tableEndInclusive, ")",
-                    " fall outside of this Range paragraphs numbers [",
-                    this._parStart, "; ", this._parEnd, ")" );
+			LOG.atWarn().log("The table's bounds [{}; {}) fall outside of this Range paragraphs numbers [{}; {})",
+					this._parStart, box(tableEndInclusive),box(this._parStart),box(this._parEnd));
         }
 
         if ( tableEndInclusive < 0 )
diff --git a/src/scratchpad/src/org/apache/poi/hwpf/usermodel/TableRow.java b/src/scratchpad/src/org/apache/poi/hwpf/usermodel/TableRow.java
index 30e1d26..9e70662 100644
--- a/src/scratchpad/src/org/apache/poi/hwpf/usermodel/TableRow.java
+++ b/src/scratchpad/src/org/apache/poi/hwpf/usermodel/TableRow.java
@@ -20,14 +20,16 @@
 import java.util.ArrayList;
 import java.util.List;
 
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.apache.poi.hwpf.sprm.SprmBuffer;
 import org.apache.poi.hwpf.sprm.TableSprmUncompressor;
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
+
+import static org.apache.logging.log4j.util.Unbox.box;
 
 public final class TableRow extends Range
 {
-    private static final POILogger LOG = POILogFactory.getLogger( TableRow.class );
+    private static final Logger LOG = LogManager.getLogger(TableRow.class);
 
     private static final short SPRM_DXAGAPHALF = (short) 0x9602;
     private static final short SPRM_DYAROWHEIGHT = (short) 0x9407;
@@ -187,11 +189,8 @@
 
         if ( cells.size() != expectedCellsCount )
         {
-            LOG.log( POILogger.WARN,
-                    "Number of found table cells (", cells.size(),
-                            ") for table row [", getStartOffset(), "c; ",
-                            getEndOffset(), "c] not equals to stored property value ",
-                            expectedCellsCount );
+            LOG.atWarn().log("Number of found table cells ({}) for table row [{}c; {}c] not equals to stored property value {}",
+                    cells.size(), box(getStartOffset()),box(getEndOffset()),box(expectedCellsCount));
             _tprops.setItcMac( (short) cells.size() );
         }
 
diff --git a/src/scratchpad/src/org/apache/poi/hwpf/util/LittleEndianCP950Reader.java b/src/scratchpad/src/org/apache/poi/hwpf/util/LittleEndianCP950Reader.java
index 3df9484..27f796c 100644
--- a/src/scratchpad/src/org/apache/poi/hwpf/util/LittleEndianCP950Reader.java
+++ b/src/scratchpad/src/org/apache/poi/hwpf/util/LittleEndianCP950Reader.java
@@ -23,9 +23,10 @@
 import java.nio.CharBuffer;
 import java.nio.charset.CharsetDecoder;
 
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+import org.apache.logging.log4j.message.SimpleMessage;
 import org.apache.poi.util.Internal;
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
 
 /**
  * Stream that converts CP950 (MSOffice's dialect of Big5), with
@@ -34,7 +35,7 @@
 @Internal
 public class LittleEndianCP950Reader extends Reader {
 
-    private static final POILogger LOGGER = POILogFactory.getLogger(LittleEndianCP950Reader.class);
+    private static final Logger LOGGER = LogManager.getLogger(LittleEndianCP950Reader.class);
 
     private static final char UNMAPPABLE = '?';
     private final ByteBuffer doubleByteBuffer = ByteBuffer.allocate(2);
@@ -107,9 +108,9 @@
             charBuffer.flip();
 
             if (charBuffer.length() == 0) {
-                LOGGER.log(POILogger.WARN, "couldn't create char for: "
+                LOGGER.atWarn().log(() -> new SimpleMessage("couldn't create char for: "
                         + Integer.toString((leading & 0xff), 16)
-                        + " " + Integer.toString((trailing & 0xff), 16));
+                        + " " + Integer.toString((trailing & 0xff), 16)));
                 return UNMAPPABLE;
             } else {
                 return Character.codePointAt(charBuffer, 0);
@@ -475,8 +476,9 @@
             case 0xfe:
                 return 0x2593;
             default:
-                LOGGER.log(POILogger.WARN, "couldn't create char for: f9"
-                        + " " + Integer.toString((trailing & 0xff), 16));
+                LOGGER.atWarn().log(() ->
+                        new SimpleMessage("couldn't create char for: f9 " + Integer.toString((trailing & 0xff), 16))
+                );
                 return UNMAPPABLE;
         }
     }
diff --git a/src/scratchpad/testcases/commons-logging.properties b/src/scratchpad/testcases/commons-logging.properties
deleted file mode 100644
index 3b4d40d..0000000
--- a/src/scratchpad/testcases/commons-logging.properties
+++ /dev/null
@@ -1,17 +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.

-

-org.apache.commons.logging.Log=org.apache.commons.logging.impl.Log4JLogger

-log4j.configuration=log4j.properties
\ No newline at end of file
diff --git a/src/scratchpad/testcases/log4j.properties b/src/scratchpad/testcases/log4j.properties
deleted file mode 100644
index 23d316d..0000000
--- a/src/scratchpad/testcases/log4j.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=ALL,CONSOLE
-
-log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
-log4j.appender.CONSOLE.target=System.out
-log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout
-log4j.appender.CONSOLE.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %c %5p %m%n
-
-log4j.logger.org.apache.fontbox.ttf=INFO
diff --git a/src/scratchpad/testcases/org/apache/poi/hwpf/HWPFTestDataSamples.java b/src/scratchpad/testcases/org/apache/poi/hwpf/HWPFTestDataSamples.java
index b4efb82..142ad02 100644
--- a/src/scratchpad/testcases/org/apache/poi/hwpf/HWPFTestDataSamples.java
+++ b/src/scratchpad/testcases/org/apache/poi/hwpf/HWPFTestDataSamples.java
@@ -22,15 +22,17 @@
 import java.io.InputStream;
 import java.util.zip.ZipInputStream;
 
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.apache.poi.POIDataSamples;
 import org.apache.poi.poifs.filesystem.POIFSFileSystem;
 import org.apache.poi.util.IOUtils;
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
+
+import static org.apache.logging.log4j.util.Unbox.box;
 
 public class HWPFTestDataSamples {
 
-    private static final POILogger LOG = POILogFactory.getLogger( HWPFTestDataSamples.class );
+    private static final Logger LOG = LogManager.getLogger(HWPFTestDataSamples.class);
 
     public static HWPFDocument openSampleFile(String sampleFileName) {
         try {
@@ -65,16 +67,13 @@
                 final long endUnzip = System.currentTimeMillis();
                 byte[] byteArray = baos.toByteArray();
 
-                LOG.log(POILogger.DEBUG, "Unzipped in ",
-                        Long.valueOf(endUnzip - start), " ms -- ",
-                        Long.valueOf(byteArray.length), " byte(s)");
+                LOG.atDebug().log("Unzipped in {} ms -- {} byte(s)", box(endUnzip - start),box(byteArray.length));
 
                 ByteArrayInputStream bais = new ByteArrayInputStream(byteArray);
                 HWPFDocument doc = new HWPFDocument(bais);
                 final long endParse = System.currentTimeMillis();
 
-                LOG.log(POILogger.DEBUG, "Parsed in ",
-                        Long.valueOf(endParse - start), " ms");
+                LOG.atDebug().log("Parsed in {} ms", box(endParse - start));
 
                 return doc;
             }
diff --git a/src/scratchpad/testcases/org/apache/poi/hwpf/usermodel/TestBugs.java b/src/scratchpad/testcases/org/apache/poi/hwpf/usermodel/TestBugs.java
index c30d801..be98329 100644
--- a/src/scratchpad/testcases/org/apache/poi/hwpf/usermodel/TestBugs.java
+++ b/src/scratchpad/testcases/org/apache/poi/hwpf/usermodel/TestBugs.java
@@ -49,8 +49,6 @@
 import org.apache.poi.hwpf.model.SubdocumentType;
 import org.apache.poi.poifs.filesystem.POIFSFileSystem;
 import org.apache.poi.util.IOUtils;
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
 import org.apache.poi.util.XMLHelper;
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.params.ParameterizedTest;
diff --git a/src/testcases/org/apache/poi/hpsf/basic/TestWrite.java b/src/testcases/org/apache/poi/hpsf/basic/TestWrite.java
index b5294bc..3718284 100644
--- a/src/testcases/org/apache/poi/hpsf/basic/TestWrite.java
+++ b/src/testcases/org/apache/poi/hpsf/basic/TestWrite.java
@@ -94,25 +94,25 @@
         "\"de_DE\".";
 
     /*
-    private static String loggerBefore;
+    private static String loggingConfigurationBefore;
 
     @BeforeClass
     public static void setUpClass() {
-        loggerBefore = System.getProperty("org.apache.poi.util.POILogger");
+        loggingConfigurationBefore = System.getProperty("log4j.configurationFile");
 
         // this test may fails in newer JDKs because of disallowed access if
         // properties are missing, make this visible
-        System.setProperty("org.apache.poi.util.POILogger", CommonsLogger.class.getName());
+        System.setProperty("log4j.configurationFile", "log4j2-console.xml");
 
         VariantSupport.setLogUnsupportedTypes(false);
     }
 
     @AfterClass
     public static void tearDownClass() {
-        if(loggerBefore == null) {
-            System.clearProperty("org.apache.poi.util.POILogger");
+        if(loggingConfigurationBefore == null) {
+            System.clearProperty("log4j.configurationFile");
         } else {
-            System.setProperty("org.apache.poi.util.POILogger", loggerBefore);
+            System.setProperty("log4j.configurationFile", loggingConfigurationBefore);
         }
     }
      */
diff --git a/src/testcases/org/apache/poi/hssf/usermodel/TestHSSFDataFormat.java b/src/testcases/org/apache/poi/hssf/usermodel/TestHSSFDataFormat.java
index 6e1698c..98195b1 100644
--- a/src/testcases/org/apache/poi/hssf/usermodel/TestHSSFDataFormat.java
+++ b/src/testcases/org/apache/poi/hssf/usermodel/TestHSSFDataFormat.java
@@ -31,8 +31,6 @@
 import org.apache.poi.ss.usermodel.CellStyle;
 import org.apache.poi.ss.usermodel.Row;
 import org.apache.poi.ss.usermodel.Sheet;
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
 import org.junit.jupiter.api.Test;
 
 /**
diff --git a/src/testcases/org/apache/poi/hssf/usermodel/TestMatrixFormulasFromBinarySpreadsheet.java b/src/testcases/org/apache/poi/hssf/usermodel/TestMatrixFormulasFromBinarySpreadsheet.java
index 6d5a9da..d56c3d6 100644
--- a/src/testcases/org/apache/poi/hssf/usermodel/TestMatrixFormulasFromBinarySpreadsheet.java
+++ b/src/testcases/org/apache/poi/hssf/usermodel/TestMatrixFormulasFromBinarySpreadsheet.java
@@ -17,6 +17,7 @@
 
 package org.apache.poi.hssf.usermodel;
 
+import static org.apache.logging.log4j.util.Unbox.box;
 import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.junit.jupiter.api.Assertions.assertNotNull;
 import static org.junit.jupiter.api.Assertions.assertTrue;
@@ -27,6 +28,8 @@
 import java.util.Locale;
 import java.util.stream.Stream;
 
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.apache.poi.hssf.HSSFTestDataSamples;
 import org.apache.poi.ss.formula.eval.ErrorEval;
 import org.apache.poi.ss.formula.functions.TestMathX;
@@ -37,8 +40,6 @@
 import org.apache.poi.ss.usermodel.Row;
 import org.apache.poi.ss.usermodel.Sheet;
 import org.apache.poi.util.LocaleUtil;
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
 import org.junit.jupiter.api.AfterAll;
 import org.junit.jupiter.params.ParameterizedTest;
 import org.junit.jupiter.params.provider.Arguments;
@@ -46,7 +47,7 @@
 
 final class TestMatrixFormulasFromBinarySpreadsheet {
 
-    private static final POILogger LOG = POILogFactory.getLogger(TestMatrixFormulasFromBinarySpreadsheet.class);
+    private static final Logger LOG = LogManager.getLogger(TestMatrixFormulasFromBinarySpreadsheet.class);
 
 
     private static HSSFWorkbook workbook;
@@ -204,14 +205,13 @@
      */
     private static String getTargetFunctionName(Row r) {
         if(r == null) {
-            LOG.log(POILogger.WARN,"Warning - given null row, can't figure out function name");
+            LOG.atWarn().log("Warning - given null row, can't figure out function name");
             return null;
         }
         Cell cell = r.getCell(Navigator.START_OPERATORS_COL_INDEX);
-        LOG.log(POILogger.INFO, String.valueOf(Navigator.START_OPERATORS_COL_INDEX));
+        LOG.atInfo().log("{}", box(Navigator.START_OPERATORS_COL_INDEX));
         if(cell == null) {
-            LOG.log(POILogger.WARN,
-                    "Warning - Row " + r.getRowNum() + " has no cell " + Navigator.START_OPERATORS_COL_INDEX + ", can't figure out function name");
+            LOG.atWarn().log("Row {} has no cell " + Navigator.START_OPERATORS_COL_INDEX + ", can't figure out function name", box(r.getRowNum()));
             return null;
         }
 
diff --git a/src/testcases/org/apache/poi/poifs/filesystem/TestEmptyDocument.java b/src/testcases/org/apache/poi/poifs/filesystem/TestEmptyDocument.java
index 73c0423..c594fb5 100644
--- a/src/testcases/org/apache/poi/poifs/filesystem/TestEmptyDocument.java
+++ b/src/testcases/org/apache/poi/poifs/filesystem/TestEmptyDocument.java
@@ -24,26 +24,20 @@
 import java.io.ByteArrayInputStream;
 import java.io.ByteArrayOutputStream;
 import java.io.IOException;
-import java.util.Arrays;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.function.Consumer;
 import java.util.stream.Stream;
 
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.apache.poi.util.IOUtils;
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
-import org.junit.jupiter.api.DisplayName;
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.params.ParameterizedTest;
 import org.junit.jupiter.params.provider.Arguments;
 import org.junit.jupiter.params.provider.MethodSource;
 
 final class TestEmptyDocument {
-    private static final POILogger LOG = POILogFactory.getLogger(TestEmptyDocument.class);
+    private static final Logger LOG = LogManager.getLogger(TestEmptyDocument.class);
 
-    private interface EmptyDoc {
+	private interface EmptyDoc {
     	void handle(DirectoryEntry dir) throws IOException;
 	}
 
@@ -61,7 +55,7 @@
 	}
 
 	private static void SingleEmptyDocumentEvent(DirectoryEntry dir) throws IOException {
-		dir.createDocument("Foo", 0, event -> LOG.log(POILogger.WARN, "written"));
+		dir.createDocument("Foo", 0, event -> LOG.atWarn().log("written"));
 	}
 
 	private static void EmptyDocumentWithFriend(DirectoryEntry dir) throws IOException {
diff --git a/src/testcases/org/apache/poi/ss/usermodel/BaseTestBugzillaIssues.java b/src/testcases/org/apache/poi/ss/usermodel/BaseTestBugzillaIssues.java
index c79abea..18e6629 100644
--- a/src/testcases/org/apache/poi/ss/usermodel/BaseTestBugzillaIssues.java
+++ b/src/testcases/org/apache/poi/ss/usermodel/BaseTestBugzillaIssues.java
@@ -17,6 +17,7 @@
 
 package org.apache.poi.ss.usermodel;
 
+import static org.apache.logging.log4j.util.Unbox.box;
 import static org.junit.jupiter.api.Assertions.assertArrayEquals;
 import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
 import static org.junit.jupiter.api.Assertions.assertEquals;
@@ -38,6 +39,8 @@
 import java.util.List;
 import java.util.Map;
 
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.apache.poi.hssf.usermodel.HSSFWorkbook;
 import org.apache.poi.ss.ITestDataProvider;
 import org.apache.poi.ss.SpreadsheetVersion;
@@ -47,8 +50,6 @@
 import org.apache.poi.ss.util.CellRangeAddressList;
 import org.apache.poi.ss.util.PaneInformation;
 import org.apache.poi.ss.util.SheetUtil;
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
 import org.junit.jupiter.api.Disabled;
 import org.junit.jupiter.api.Test;
 
@@ -56,7 +57,7 @@
  * A base class for bugzilla issues that can be described in terms of common ss interfaces.
  */
 public abstract class BaseTestBugzillaIssues {
-    private static final POILogger LOG = POILogFactory.getLogger(BaseTestBugzillaIssues.class);
+    private static final Logger LOG = LogManager.getLogger(BaseTestBugzillaIssues.class);
 
     private static final String TEST_32 = "Some text with 32 characters to ";
     private static final String TEST_255 = "Some very long text that is exactly 255 characters, which are allowed here, bla bla, bla bla, bla bla, bla bla, bla bla, bla bla, bla bla, bla bla, bla bla, bla bla, bla bla, bla bla, bla bla, bla bla, bla bla, bla bla, bla bla, bla bla, bla bla, bla.....";
@@ -1387,7 +1388,7 @@
         // Create a workbook
         try (Workbook wb = _testDataProvider.createWorkbook(nrows+1)) {
             final Sheet sh = wb.createSheet();
-            LOG.log(POILogger.DEBUG, wb.getClass().getName(), " column autosizing timing...");
+            LOG.atDebug().log("{} column autosizing timing...", wb.getClass().getName());
 
             final long t0 = time();
             _testDataProvider.trackAllColumnsForAutosizing(sh);
@@ -1400,28 +1401,24 @@
             }
             final double populateSheetTime = delta(t0);
             final double populateSheetTimePerCell_ns = (1000000 * populateSheetTime / (nrows * ncols));
-            if (LOG.check(POILogger.DEBUG)) {
-                LOG.log(POILogger.DEBUG, "Populate sheet time: ", populateSheetTime, " ms (", populateSheetTimePerCell_ns, " ns/cell)");
+            LOG.atDebug().log("Populate sheet time: {} ms ({} ns/cell)", populateSheetTime, populateSheetTimePerCell_ns);
 
-                LOG.log(POILogger.DEBUG, "Autosizing...");
-            }
+            LOG.atDebug().log("Autosizing...");
             final long t1 = time();
             for (int c = 0; c < ncols; c++) {
                 final long t2 = time();
                 sh.autoSizeColumn(c);
-                LOG.log(POILogger.DEBUG, "Column ", c, " took ", delta(t2), " ms");
+                LOG.atDebug().log("Column {} took {} ms", box(c),delta(t2));
             }
             final double autoSizeColumnsTime = delta(t1);
             final double autoSizeColumnsTimePerColumn = autoSizeColumnsTime / ncols;
             final double bestFitWidthTimePerCell_ns = 1000000 * autoSizeColumnsTime / (ncols * nrows);
 
-            if (LOG.check(POILogger.DEBUG)) {
-                LOG.log(POILogger.DEBUG, "Auto sizing columns took a total of ", autoSizeColumnsTime, " ms (", autoSizeColumnsTimePerColumn, " ms per column)");
-                LOG.log(POILogger.DEBUG, "Best fit width time per cell: ", bestFitWidthTimePerCell_ns, " ns");
-            }
+            LOG.atDebug().log("Auto sizing columns took a total of {} ms ({} ms per column)", autoSizeColumnsTime, autoSizeColumnsTimePerColumn);
+            LOG.atDebug().log("Best fit width time per cell: {} ns", bestFitWidthTimePerCell_ns);
 
             final double totalTime_s = (populateSheetTime + autoSizeColumnsTime) / 1000;
-            LOG.log(POILogger.DEBUG, "Total time: ", totalTime_s, " s");
+            LOG.atDebug().log("Total time: {} s", totalTime_s);
         }
 
         //if (bestFitWidthTimePerCell_ns > 50000) {
diff --git a/src/testcases/org/apache/poi/util/DummyPOILogger.java b/src/testcases/org/apache/poi/util/DummyPOILogger.java
deleted file mode 100644
index bb6526b..0000000
--- a/src/testcases/org/apache/poi/util/DummyPOILogger.java
+++ /dev/null
@@ -1,51 +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.poi.util;
-
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * {@link POILogger} which logs into an ArrayList so that
- *  tests can see what got logged
- */
-@Internal
-public class DummyPOILogger implements POILogger {
-	public List<String>logged = new ArrayList<>();
-
-	public void reset() {
-		logged = new ArrayList<>();
-	}
-
-    @Override
-	public boolean check(int level) {
-		return true;
-	}
-
-    @Override
-	public void initialize(String cat) {}
-
-    @Override
-	public void _log(int level, Object obj1) {
-		logged.add(level + " - " + obj1);
-	}
-
-    @Override
-	public void _log(int level, Object obj1, Throwable exception) {
-		logged.add(level + " - " + obj1 + " - " + exception);
-	}
-}
diff --git a/src/testcases/org/apache/poi/util/TestPOILogger.java b/src/testcases/org/apache/poi/util/TestPOILogger.java
deleted file mode 100644
index 4829ca2..0000000
--- a/src/testcases/org/apache/poi/util/TestPOILogger.java
+++ /dev/null
@@ -1,83 +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.poi.util;
-
-import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertNotNull;
-import static org.junit.jupiter.api.Assertions.assertTrue;
-
-import org.junit.jupiter.api.Test;
-
-/**
- * Tests the log class.
- */
-public final class TestPOILogger implements POILogger {
-    private String lastLog = "";
-    private Throwable lastEx;
-
-    /**
-     * Test different types of log output.
-     */
-    @Test
-    void testVariousLogTypes() throws Exception {
-        String oldLCN = POILogFactory._loggerClassName;
-        try {
-            POILogFactory._loggerClassName = TestPOILogger.class.getName();
-            POILogger log = POILogFactory.getLogger( "foo" );
-            assertTrue(log instanceof TestPOILogger);
-
-            TestPOILogger tLog = (TestPOILogger)log;
-
-            log.log(POILogger.WARN, "Test = ", 1);
-            assertEquals("Test = 1", tLog.lastLog);
-
-            log.log(POILogger.ERROR, "Test ", 1,2,new Exception("bla"));
-            assertEquals("Test 12", tLog.lastLog);
-            assertNotNull(tLog.lastEx);
-
-            log.log(POILogger.ERROR, "log\nforging", "\nevil","\nlog");
-            assertEquals("log forging evil log", tLog.lastLog);
-        } finally {
-            POILogFactory._loggerClassName = oldLCN;
-        }
-    }
-
-    // ---------- POI Logger methods implemented for testing ----------
-
-    @Override
-    public void initialize(String cat) {
-    }
-
-    @Override
-    public void _log(int level, Object obj1) {
-        lastLog = (obj1 == null) ? "" : obj1.toString();
-        lastEx = null;
-    }
-
-    @Override
-    public void _log(int level, Object obj1, Throwable exception) {
-        lastLog = (obj1 == null) ? "" : obj1.toString();
-        lastEx = exception;
-    }
-
-    @Override
-    public boolean check(int level) {
-        return true;
-    }
-}