From 219901211e0abcbd24e16a52c5b0f689841db807 Mon Sep 17 00:00:00 2001
From: David Solin <solind@Gallifrey.local>
Date: Tue, 23 Aug 2016 19:13:43 -0500
Subject: [PATCH 1/7] Changes for injecting a LoggingFactory.

---
 .../transport/IdentificationStringParser.java |  17 +--
 .../java/net/schmizz/concurrent/Event.java    |  10 +-
 .../java/net/schmizz/concurrent/Promise.java  |  13 ++-
 .../java/net/schmizz/keepalive/KeepAlive.java |   4 +-
 .../net/schmizz/sshj/AbstractService.java     |   5 +-
 src/main/java/net/schmizz/sshj/Config.java    |  11 ++
 .../java/net/schmizz/sshj/ConfigImpl.java     |  12 ++
 .../java/net/schmizz/sshj/DefaultConfig.java  |  53 +++++++--
 src/main/java/net/schmizz/sshj/SSHClient.java |  14 ++-
 .../java/net/schmizz/sshj/common/IOUtils.java |  23 ++--
 .../java/net/schmizz/sshj/common/KeyType.java |   6 +-
 .../net/schmizz/sshj/common/StreamCopier.java |  12 +-
 .../schmizz/sshj/connection/Connection.java   |   3 +-
 .../sshj/connection/ConnectionImpl.java       |   2 +-
 .../connection/channel/AbstractChannel.java   |  21 ++--
 .../sshj/connection/channel/Channel.java      |   5 +
 .../channel/ChannelInputStream.java           |   3 +-
 .../sshj/connection/channel/Window.java       |  15 +--
 .../channel/direct/AbstractDirectChannel.java |   3 +-
 .../channel/direct/LocalPortForwarder.java    |  14 ++-
 .../forwarded/AbstractForwardedChannel.java   |   2 +-
 .../AbstractForwardedChannelOpener.java       |   6 +-
 .../SocketForwardingConnectListener.java      |  10 +-
 .../net/schmizz/sshj/sftp/PacketReader.java   |   5 +-
 .../schmizz/sshj/sftp/RemoteDirectory.java    |   2 +-
 .../net/schmizz/sshj/sftp/RemoteFile.java     |   2 +-
 .../net/schmizz/sshj/sftp/RemoteResource.java |   7 +-
 .../net/schmizz/sshj/sftp/SFTPClient.java     |   3 +-
 .../net/schmizz/sshj/sftp/SFTPEngine.java     |  20 +++-
 .../schmizz/sshj/sftp/SFTPFileTransfer.java   |   5 +-
 .../net/schmizz/sshj/transport/Decoder.java   |   6 +-
 .../net/schmizz/sshj/transport/Encoder.java   |  11 +-
 .../schmizz/sshj/transport/KeyExchanger.java  |  11 +-
 .../net/schmizz/sshj/transport/Reader.java    |   4 +-
 .../net/schmizz/sshj/transport/Transport.java |   3 +-
 .../schmizz/sshj/transport/TransportImpl.java |  56 ++++++----
 .../verification/OpenSSHKnownHosts.java       | 103 ++++++++++--------
 .../schmizz/sshj/userauth/UserAuthImpl.java   |   4 +-
 .../userauth/method/AbstractAuthMethod.java   |   9 +-
 .../sshj/userauth/method/AuthMethod.java      |   2 +
 .../method/PasswordResponseProvider.java      |  10 +-
 .../sshj/xfer/AbstractFileTransfer.java       |  21 +++-
 .../sshj/xfer/LoggingTransferListener.java    |  15 ++-
 .../net/schmizz/sshj/xfer/scp/SCPEngine.java  |  15 ++-
 .../sshj/xfer/scp/SCPFileTransfer.java        |   6 +-
 45 files changed, 370 insertions(+), 214 deletions(-)

diff --git a/src/main/java/com/hierynomus/sshj/transport/IdentificationStringParser.java b/src/main/java/com/hierynomus/sshj/transport/IdentificationStringParser.java
index d1591561d..a4cbd6be2 100644
--- a/src/main/java/com/hierynomus/sshj/transport/IdentificationStringParser.java
+++ b/src/main/java/com/hierynomus/sshj/transport/IdentificationStringParser.java
@@ -17,20 +17,21 @@
 
 import net.schmizz.sshj.common.Buffer;
 import net.schmizz.sshj.common.ByteArrayUtils;
+import net.schmizz.sshj.common.LoggerFactory;
 import net.schmizz.sshj.transport.TransportException;
 import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 
 import java.io.IOException;
 import java.util.Arrays;
 
 public class IdentificationStringParser {
-    private static final Logger logger = LoggerFactory.getLogger(IdentificationStringParser.class);
+    private final Logger log;
     private final Buffer.PlainBuffer buffer;
 
     private byte[] EXPECTED_START_BYTES = new byte[] {'S', 'S', 'H', '-'};
 
-    public IdentificationStringParser(Buffer.PlainBuffer buffer) {
+    public IdentificationStringParser(LoggerFactory loggerFactory, Buffer.PlainBuffer buffer) {
+	this.log = loggerFactory.getLogger(IdentificationStringParser.class);
         this.buffer = buffer;
     }
 
@@ -65,16 +66,16 @@ private String readIdentification(Buffer.PlainBuffer lineBuffer) throws Buffer.B
         byte[] bytes = new byte[lineBuffer.available()];
         lineBuffer.readRawBytes(bytes);
         if (bytes.length > 255) {
-            logger.error("Incorrect identification String received, line was longer than expected: {}", new String(bytes));
-            logger.error("Just for good measure, bytes were: {}", ByteArrayUtils.printHex(bytes, 0, bytes.length));
+            log.error("Incorrect identification String received, line was longer than expected: {}", new String(bytes));
+            log.error("Just for good measure, bytes were: {}", ByteArrayUtils.printHex(bytes, 0, bytes.length));
             throw new TransportException("Incorrect identification: line too long: " + ByteArrayUtils.printHex(bytes, 0, bytes.length));
         }
         if (bytes[bytes.length - 2] != '\r') {
             String ident = new String(bytes, 0, bytes.length - 1);
-            logger.warn("Server identification has bad line ending, was expecting a '\\r\\n' however got: '{}' (hex: {})", (char) (bytes[bytes.length - 2] & 0xFF), Integer.toHexString(bytes[bytes.length - 2] & 0xFF));
-            logger.warn("Will treat the identification of this server '{}' leniently", ident);
+            log.warn("Server identification has bad line ending, was expecting a '\\r\\n' however got: '{}' (hex: {})", (char) (bytes[bytes.length - 2] & 0xFF), Integer.toHexString(bytes[bytes.length - 2] & 0xFF));
+            log.warn("Will treat the identification of this server '{}' leniently", ident);
             return ident;
-            // logger.error("Data received up til here was: {}", new String(bytes));
+            // log.error("Data received up til here was: {}", new String(bytes));
             // throw new TransportException("Incorrect identification: bad line ending: " + ByteArrayUtils.toHex(bytes, 0, bytes.length));
         }
 
diff --git a/src/main/java/net/schmizz/concurrent/Event.java b/src/main/java/net/schmizz/concurrent/Event.java
index 72f565bfd..b5a449fb3 100644
--- a/src/main/java/net/schmizz/concurrent/Event.java
+++ b/src/main/java/net/schmizz/concurrent/Event.java
@@ -18,6 +18,8 @@
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.locks.ReentrantLock;
 
+import net.schmizz.sshj.common.LoggerFactory;
+
 /**
  * An event can be set, cleared, or awaited, similar to Python's {@code threading.event}. The key difference is that a
  * waiter may be delivered an exception of parameterized type {@code T}.
@@ -42,8 +44,8 @@ public String toString() {
      * @param name    name of this event
      * @param chainer {@link ExceptionChainer} that will be used for chaining exceptions
      */
-    public Event(String name, ExceptionChainer<T> chainer) {
-        promise = new Promise<Object, T>(name, chainer);
+    public Event(String name, ExceptionChainer<T> chainer, LoggerFactory loggerFactory) {
+        promise = new Promise<Object, T>(name, chainer, loggerFactory);
     }
 
     /**
@@ -53,8 +55,8 @@ public Event(String name, ExceptionChainer<T> chainer) {
      * @param chainer {@link ExceptionChainer} that will be used for chaining exceptions
      * @param lock    lock to use
      */
-    public Event(String name, ExceptionChainer<T> chainer, ReentrantLock lock) {
-        promise = new Promise<Object, T>(name, chainer, lock);
+    public Event(String name, ExceptionChainer<T> chainer, ReentrantLock lock, LoggerFactory loggerFactory) {
+        promise = new Promise<Object, T>(name, chainer, lock, loggerFactory);
     }
 
     /** Sets this event to be {@code true}. Short for {@code set(true)}. */
diff --git a/src/main/java/net/schmizz/concurrent/Promise.java b/src/main/java/net/schmizz/concurrent/Promise.java
index d568eacdf..f85080c5d 100644
--- a/src/main/java/net/schmizz/concurrent/Promise.java
+++ b/src/main/java/net/schmizz/concurrent/Promise.java
@@ -16,13 +16,14 @@
 package net.schmizz.concurrent;
 
 import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.TimeoutException;
 import java.util.concurrent.locks.Condition;
 import java.util.concurrent.locks.ReentrantLock;
 
+import net.schmizz.sshj.common.LoggerFactory;
+
 /**
  * Represents promised data of the parameterized type {@code V} and allows waiting on it. An exception may also be
  * delivered to a waiter, and will be of the parameterized type {@code T}.
@@ -32,8 +33,7 @@
  */
 public class Promise<V, T extends Throwable> {
 
-    private final Logger log = LoggerFactory.getLogger(getClass());
-
+    private final Logger log;
     private final String name;
     private final ExceptionChainer<T> chainer;
     private final ReentrantLock lock;
@@ -49,8 +49,8 @@ public class Promise<V, T extends Throwable> {
      * @param name    name of this promise
      * @param chainer {@link ExceptionChainer} that will be used for chaining exceptions
      */
-    public Promise(String name, ExceptionChainer<T> chainer) {
-        this(name, chainer, null);
+    public Promise(String name, ExceptionChainer<T> chainer, LoggerFactory loggerFactory) {
+        this(name, chainer, null, loggerFactory);
     }
 
     /**
@@ -60,10 +60,11 @@ public Promise(String name, ExceptionChainer<T> chainer) {
      * @param chainer {@link ExceptionChainer} that will be used for chaining exceptions
      * @param lock    lock to use
      */
-    public Promise(String name, ExceptionChainer<T> chainer, ReentrantLock lock) {
+    public Promise(String name, ExceptionChainer<T> chainer, ReentrantLock lock, LoggerFactory loggerFactory) {
         this.name = name;
         this.chainer = chainer;
         this.lock = lock == null ? new ReentrantLock() : lock;
+	this.log = loggerFactory.getLogger(getClass());
         this.cond = this.lock.newCondition();
     }
 
diff --git a/src/main/java/net/schmizz/keepalive/KeepAlive.java b/src/main/java/net/schmizz/keepalive/KeepAlive.java
index 4ab397460..c5972c5f8 100644
--- a/src/main/java/net/schmizz/keepalive/KeepAlive.java
+++ b/src/main/java/net/schmizz/keepalive/KeepAlive.java
@@ -22,14 +22,14 @@
 import org.slf4j.LoggerFactory;
 
 public abstract class KeepAlive extends Thread {
-    protected final Logger log = LoggerFactory.getLogger(getClass());
-
+    protected final Logger log;
     protected final ConnectionImpl conn;
 
     protected int keepAliveInterval = 0;
 
     protected KeepAlive(ConnectionImpl conn, String name) {
         this.conn = conn;
+        log = conn.getTransport().getConfig().getLoggerFactory().getLogger(getClass());
         setName(name);
     }
 
diff --git a/src/main/java/net/schmizz/sshj/AbstractService.java b/src/main/java/net/schmizz/sshj/AbstractService.java
index e2236ff51..2eb4b615f 100644
--- a/src/main/java/net/schmizz/sshj/AbstractService.java
+++ b/src/main/java/net/schmizz/sshj/AbstractService.java
@@ -16,20 +16,20 @@
 package net.schmizz.sshj;
 
 import net.schmizz.sshj.common.DisconnectReason;
+import net.schmizz.sshj.common.LoggerFactory;
 import net.schmizz.sshj.common.Message;
 import net.schmizz.sshj.common.SSHException;
 import net.schmizz.sshj.common.SSHPacket;
 import net.schmizz.sshj.transport.Transport;
 import net.schmizz.sshj.transport.TransportException;
 import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 
 /** An abstract class for {@link Service} that implements common or default functionality. */
 public abstract class AbstractService
         implements Service {
 
     /** Logger */
-    protected final Logger log = LoggerFactory.getLogger(getClass());
+    protected final Logger log;
 
     /** Assigned name of this service */
     protected final String name;
@@ -39,6 +39,7 @@ public abstract class AbstractService
     public AbstractService(String name, Transport trans) {
         this.name = name;
         this.trans = trans;
+	log = trans.getConfig().getLoggerFactory().getLogger(getClass());
     }
 
     @Override
diff --git a/src/main/java/net/schmizz/sshj/Config.java b/src/main/java/net/schmizz/sshj/Config.java
index 9bb9453c6..d973adf28 100644
--- a/src/main/java/net/schmizz/sshj/Config.java
+++ b/src/main/java/net/schmizz/sshj/Config.java
@@ -17,6 +17,7 @@
 
 import net.schmizz.keepalive.KeepAliveProvider;
 import net.schmizz.sshj.common.Factory;
+import net.schmizz.sshj.common.LoggerFactory;
 import net.schmizz.sshj.signature.Signature;
 import net.schmizz.sshj.transport.cipher.Cipher;
 import net.schmizz.sshj.transport.compression.Compression;
@@ -175,4 +176,14 @@ public interface Config {
      * @param waitForServerIdentBeforeSendingClientIdent Whether to wait for the server ident.
      */
     void setWaitForServerIdentBeforeSendingClientIdent(boolean waitForServerIdentBeforeSendingClientIdent);
+
+    /**
+     * Sets the LoggerFactory to use.
+     */
+    void setLoggerFactory(LoggerFactory loggerFactory);
+
+    /**
+     * @return The LoggerFactory the SSHClient will use.
+     */
+    LoggerFactory getLoggerFactory();
 }
diff --git a/src/main/java/net/schmizz/sshj/ConfigImpl.java b/src/main/java/net/schmizz/sshj/ConfigImpl.java
index b070c3946..fce2cfda8 100644
--- a/src/main/java/net/schmizz/sshj/ConfigImpl.java
+++ b/src/main/java/net/schmizz/sshj/ConfigImpl.java
@@ -16,6 +16,7 @@
 package net.schmizz.sshj;
 
 import net.schmizz.keepalive.KeepAliveProvider;
+import net.schmizz.sshj.common.LoggerFactory;
 import net.schmizz.sshj.common.Factory;
 import net.schmizz.sshj.signature.Signature;
 import net.schmizz.sshj.transport.cipher.Cipher;
@@ -45,6 +46,7 @@ public class ConfigImpl
     private List<Factory.Named<FileKeyProvider>> fileKeyProviderFactories;
 
     private boolean waitForServerIdentBeforeSendingClientIdent = false;
+    private LoggerFactory loggerFactory;
 
     @Override
     public List<Factory.Named<Cipher>> getCipherFactories() {
@@ -169,4 +171,14 @@ public boolean isWaitForServerIdentBeforeSendingClientIdent() {
     public void setWaitForServerIdentBeforeSendingClientIdent(boolean waitForServerIdentBeforeSendingClientIdent) {
         this.waitForServerIdentBeforeSendingClientIdent = waitForServerIdentBeforeSendingClientIdent;
     }
+
+    @Override
+    public LoggerFactory getLoggerFactory() {
+        return loggerFactory;
+    }
+
+    @Override
+    public void setLoggerFactory(LoggerFactory loggerFactory) {
+        this.loggerFactory = loggerFactory;
+    }
 }
diff --git a/src/main/java/net/schmizz/sshj/DefaultConfig.java b/src/main/java/net/schmizz/sshj/DefaultConfig.java
index 3db2685aa..c500d0231 100644
--- a/src/main/java/net/schmizz/sshj/DefaultConfig.java
+++ b/src/main/java/net/schmizz/sshj/DefaultConfig.java
@@ -20,6 +20,7 @@
 import com.hierynomus.sshj.transport.cipher.StreamCiphers;
 import net.schmizz.keepalive.KeepAliveProvider;
 import net.schmizz.sshj.common.Factory;
+import net.schmizz.sshj.common.LoggerFactory;
 import net.schmizz.sshj.common.SecurityUtils;
 import net.schmizz.sshj.signature.SignatureDSA;
 import net.schmizz.sshj.signature.SignatureECDSA;
@@ -35,7 +36,6 @@
 import net.schmizz.sshj.userauth.keyprovider.PKCS8KeyFile;
 import net.schmizz.sshj.userauth.keyprovider.PuTTYKeyFile;
 import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 
 import java.util.Arrays;
 import java.util.Iterator;
@@ -67,11 +67,12 @@
 public class DefaultConfig
         extends ConfigImpl {
 
-    private final Logger log = LoggerFactory.getLogger(getClass());
-
     private static final String VERSION = "SSHJ_0_17_2";
 
+    private Logger log;
+
     public DefaultConfig() {
+        setLoggerFactory(LoggerFactory.DEFAULT);
         setVersion(VERSION);
         final boolean bouncyCastleRegistered = SecurityUtils.isBouncyCastleRegistered();
         initKeyExchangeFactories(bouncyCastleRegistered);
@@ -84,6 +85,30 @@ public DefaultConfig() {
         setKeepAliveProvider(KeepAliveProvider.HEARTBEAT);
     }
 
+    /**
+     * Default SLF4J-based implementation of the SSHJ LoggerFactory.
+     */
+    public static class DefaultLoggerFactory implements LoggerFactory {
+        private DefaultLoggerFactory() {
+        }
+
+        @Override
+        public Logger getLogger(String name) {
+            return org.slf4j.LoggerFactory.getLogger(name);
+        }
+
+        @Override
+        public Logger getLogger(Class<?> clazz) {
+            return org.slf4j.LoggerFactory.getLogger(clazz);
+        }
+    }
+
+    @Override
+    public void setLoggerFactory(LoggerFactory loggerFactory) {
+	super.setLoggerFactory(loggerFactory);
+	log = loggerFactory.getLogger(getClass());
+    }
+
     protected void initKeyExchangeFactories(boolean bouncyCastleRegistered) {
         if (bouncyCastleRegistered)
             setKeyExchangeFactories(new Curve25519SHA256.Factory(),
@@ -141,7 +166,8 @@ protected void initCipherFactories() {
                 BlockCiphers.TwofishCBC(),
                 StreamCiphers.Arcfour(),
                 StreamCiphers.Arcfour128(),
-                StreamCiphers.Arcfour256()));
+                StreamCiphers.Arcfour256())
+        );
 
         boolean warn = false;
         // Ref. https://issues.apache.org/jira/browse/SSHD-24
@@ -167,17 +193,26 @@ protected void initCipherFactories() {
     }
 
     protected void initSignatureFactories() {
-        setSignatureFactories(new SignatureECDSA.Factory(), new SignatureRSA.Factory(), new SignatureDSA.Factory(), new SignatureEdDSA.Factory());
+        setSignatureFactories(
+                new SignatureECDSA.Factory(),
+                new SignatureRSA.Factory(),
+                new SignatureDSA.Factory(),
+                new SignatureEdDSA.Factory()
+        );
     }
 
     protected void initMACFactories() {
-        setMACFactories(new HMACSHA1.Factory(), new HMACSHA196.Factory(), new HMACMD5.Factory(),
-                new HMACMD596.Factory(), new HMACSHA2256.Factory(), new HMACSHA2512.Factory());
+        setMACFactories(
+                new HMACSHA1.Factory(),
+                new HMACSHA196.Factory(),
+                new HMACMD5.Factory(),
+                new HMACMD596.Factory(),
+                new HMACSHA2256.Factory(),
+                new HMACSHA2512.Factory()
+        );
     }
 
     protected void initCompressionFactories() {
         setCompressionFactories(new NoneCompression.Factory());
     }
-
-
 }
diff --git a/src/main/java/net/schmizz/sshj/SSHClient.java b/src/main/java/net/schmizz/sshj/SSHClient.java
index 1b62fd035..deef70c41 100644
--- a/src/main/java/net/schmizz/sshj/SSHClient.java
+++ b/src/main/java/net/schmizz/sshj/SSHClient.java
@@ -16,6 +16,7 @@
 package net.schmizz.sshj;
 
 import net.schmizz.sshj.common.Factory;
+import net.schmizz.sshj.common.LoggerFactory;
 import net.schmizz.sshj.common.SSHException;
 import net.schmizz.sshj.common.SecurityUtils;
 import net.schmizz.sshj.connection.Connection;
@@ -54,7 +55,6 @@
 import net.schmizz.sshj.xfer.scp.SCPFileTransfer;
 import org.ietf.jgss.Oid;
 import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 
 import javax.security.auth.login.LoginContext;
 import java.io.Closeable;
@@ -114,7 +114,8 @@ public class SSHClient
     public static final int DEFAULT_PORT = 22;
 
     /** Logger */
-    protected final Logger log = LoggerFactory.getLogger(getClass());
+    protected final LoggerFactory loggerFactory;
+    protected final Logger log;
 
     /** Transport layer */
     protected final Transport trans;
@@ -139,6 +140,8 @@ public SSHClient() {
      */
     public SSHClient(Config config) {
         super(DEFAULT_PORT);
+	loggerFactory = config.getLoggerFactory();
+	log = loggerFactory.getLogger(getClass());
         this.trans = new TransportImpl(config, this);
         this.auth = new UserAuthImpl(trans);
         this.conn = new ConnectionImpl(trans, config.getKeepAliveProvider());
@@ -211,6 +214,7 @@ public void auth(String username, Iterable<AuthMethod> methods)
         checkConnected();
         final Deque<UserAuthException> savedEx = new LinkedList<>();
         for (AuthMethod method: methods) {
+            method.setLoggerFactory(loggerFactory);
             try {
                 if (auth.authenticate(username, (Service) conn, method, trans.getTimeoutMs()))
                     return;
@@ -626,7 +630,7 @@ public void loadKnownHosts()
      */
     public void loadKnownHosts(File location)
             throws IOException {
-        addHostKeyVerifier(new OpenSSHKnownHosts(location));
+        addHostKeyVerifier(new OpenSSHKnownHosts(location, loggerFactory));
     }
 
     /**
@@ -644,7 +648,7 @@ public void loadKnownHosts(File location)
      */
     public LocalPortForwarder newLocalPortForwarder(LocalPortForwarder.Parameters parameters,
                                                     ServerSocket serverSocket) {
-        LocalPortForwarder forwarder = new LocalPortForwarder(conn, parameters, serverSocket);
+        LocalPortForwarder forwarder = new LocalPortForwarder(conn, parameters, serverSocket, loggerFactory);
         forwarders.add(forwarder);
         return forwarder;
     }
@@ -673,7 +677,7 @@ public X11Forwarder registerX11Forwarder(ConnectListener listener) {
     public SCPFileTransfer newSCPFileTransfer() {
         checkConnected();
         checkAuthenticated();
-        return new SCPFileTransfer(this);
+        return new SCPFileTransfer(this, loggerFactory);
     }
 
     /**
diff --git a/src/main/java/net/schmizz/sshj/common/IOUtils.java b/src/main/java/net/schmizz/sshj/common/IOUtils.java
index 53f3ada5e..9421f8387 100644
--- a/src/main/java/net/schmizz/sshj/common/IOUtils.java
+++ b/src/main/java/net/schmizz/sshj/common/IOUtils.java
@@ -16,7 +16,6 @@
 package net.schmizz.sshj.common;
 
 import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 
 import java.io.ByteArrayOutputStream;
 import java.io.Closeable;
@@ -26,25 +25,33 @@
 
 public class IOUtils {
 
-    private static final Logger LOG = LoggerFactory.getLogger(IOUtils.class);
-
     public static final Charset UTF8 = Charset.forName("UTF-8");
 
     public static void closeQuietly(Closeable... closeables) {
-        for (Closeable c : closeables)
+        closeQuietly(LoggerFactory.DEFAULT, closeables);
+    }
+
+    public static ByteArrayOutputStream readFully(InputStream stream)
+            throws IOException {
+        return readFully(stream, LoggerFactory.DEFAULT);
+    }
+
+    public static void closeQuietly(LoggerFactory loggerFactory, Closeable... closeables) {
+        for (Closeable c : closeables) {
             try {
                 if (c != null)
                     c.close();
             } catch (IOException logged) {
-                LOG.warn("Error closing {} - {}", c, logged);
+		loggerFactory.getLogger(IOUtils.class).warn("Error closing {} - {}", c, logged);
             }
+        }
     }
 
-    public static ByteArrayOutputStream readFully(InputStream stream)
+    public static ByteArrayOutputStream readFully(InputStream stream, LoggerFactory loggerFactory)
             throws IOException {
         final ByteArrayOutputStream baos = new ByteArrayOutputStream();
-        new StreamCopier(stream, baos).copy();
+        new StreamCopier(stream, baos, loggerFactory).copy();
         return baos;
     }
 
-}
\ No newline at end of file
+}
diff --git a/src/main/java/net/schmizz/sshj/common/KeyType.java b/src/main/java/net/schmizz/sshj/common/KeyType.java
index 4dcc97eda..a2458323b 100644
--- a/src/main/java/net/schmizz/sshj/common/KeyType.java
+++ b/src/main/java/net/schmizz/sshj/common/KeyType.java
@@ -174,15 +174,15 @@ protected boolean isMyType(Key key) {
     },
 
     ED25519("ssh-ed25519") {
-        private final Logger logger = LoggerFactory.getLogger(KeyType.class);
+        private final Logger log = LoggerFactory.getLogger(KeyType.class);
         @Override
         public PublicKey readPubKeyFromBuffer(String type, Buffer<?> buf) throws GeneralSecurityException {
             try {
                 final int keyLen = buf.readUInt32AsInt();
                 final byte[] p = new byte[keyLen];
                 buf.readRawBytes(p);
-                if (logger.isDebugEnabled()) {
-                    logger.debug(String.format("Key algo: %s, Key curve: 25519, Key Len: %s\np: %s",
+                if (log.isDebugEnabled()) {
+                    log.debug(String.format("Key algo: %s, Key curve: 25519, Key Len: %s\np: %s",
                             type,
                             keyLen,
                             Arrays.toString(p))
diff --git a/src/main/java/net/schmizz/sshj/common/StreamCopier.java b/src/main/java/net/schmizz/sshj/common/StreamCopier.java
index 18e228de9..8260b92e6 100644
--- a/src/main/java/net/schmizz/sshj/common/StreamCopier.java
+++ b/src/main/java/net/schmizz/sshj/common/StreamCopier.java
@@ -15,10 +15,10 @@
  */
 package net.schmizz.sshj.common;
 
+import net.schmizz.sshj.common.LoggerFactory;
 import net.schmizz.concurrent.Event;
 import net.schmizz.concurrent.ExceptionChainer;
 import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 
 import java.io.IOException;
 import java.io.InputStream;
@@ -39,8 +39,8 @@ public void reportProgress(long transferred) {
         }
     };
 
-    private final Logger log = LoggerFactory.getLogger(getClass());
-
+    private final LoggerFactory loggerFactory;
+    private final Logger log;
     private final InputStream in;
     private final OutputStream out;
 
@@ -50,9 +50,11 @@ public void reportProgress(long transferred) {
     private boolean keepFlushing = true;
     private long length = -1;
 
-    public StreamCopier(InputStream in, OutputStream out) {
+    public StreamCopier(InputStream in, OutputStream out, LoggerFactory loggerFactory) {
         this.in = in;
         this.out = out;
+        this.loggerFactory = loggerFactory;
+        this.log = loggerFactory.getLogger(getClass());
     }
 
     public StreamCopier bufSize(int bufSize) {
@@ -91,7 +93,7 @@ private Event<IOException> spawn(final String name, final boolean daemon) {
                     public IOException chain(Throwable t) {
                         return (t instanceof IOException) ? (IOException) t : new IOException(t);
                     }
-                });
+                }, loggerFactory);
 
         new Thread() {
             {
diff --git a/src/main/java/net/schmizz/sshj/connection/Connection.java b/src/main/java/net/schmizz/sshj/connection/Connection.java
index 257e86ebd..d08bb4ae2 100644
--- a/src/main/java/net/schmizz/sshj/connection/Connection.java
+++ b/src/main/java/net/schmizz/sshj/connection/Connection.java
@@ -17,6 +17,7 @@
 
 import net.schmizz.concurrent.Promise;
 import net.schmizz.keepalive.KeepAlive;
+import net.schmizz.sshj.common.LoggerFactory;
 import net.schmizz.sshj.common.SSHPacket;
 import net.schmizz.sshj.connection.channel.Channel;
 import net.schmizz.sshj.connection.channel.OpenFailException;
@@ -156,4 +157,4 @@ void sendOpenFailure(int recipient, OpenFailException.Reason reason, String mess
      * @return The configured {@link net.schmizz.keepalive.KeepAlive} mechanism.
      */
     KeepAlive getKeepAlive();
-}
\ No newline at end of file
+}
diff --git a/src/main/java/net/schmizz/sshj/connection/ConnectionImpl.java b/src/main/java/net/schmizz/sshj/connection/ConnectionImpl.java
index 6fa7ca47b..1a7b2ce5c 100644
--- a/src/main/java/net/schmizz/sshj/connection/ConnectionImpl.java
+++ b/src/main/java/net/schmizz/sshj/connection/ConnectionImpl.java
@@ -199,7 +199,7 @@ public Promise<SSHPacket, ConnectionException> sendGlobalRequest(String name, bo
 
             Promise<SSHPacket, ConnectionException> promise = null;
             if (wantReply) {
-                promise = new Promise<SSHPacket, ConnectionException>("global req for " + name, ConnectionException.chainer);
+                promise = new Promise<SSHPacket, ConnectionException>("global req for " + name, ConnectionException.chainer, trans.getConfig().getLoggerFactory());
                 globalReqPromises.add(promise);
             }
             return promise;
diff --git a/src/main/java/net/schmizz/sshj/connection/channel/AbstractChannel.java b/src/main/java/net/schmizz/sshj/connection/channel/AbstractChannel.java
index 647c64dd4..215f14bd6 100644
--- a/src/main/java/net/schmizz/sshj/connection/channel/AbstractChannel.java
+++ b/src/main/java/net/schmizz/sshj/connection/channel/AbstractChannel.java
@@ -23,7 +23,6 @@
 import net.schmizz.sshj.transport.Transport;
 import net.schmizz.sshj.transport.TransportException;
 import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 
 import java.io.InputStream;
 import java.io.OutputStream;
@@ -38,7 +37,8 @@ public abstract class AbstractChannel
     private static final int REMOTE_MAX_PACKET_SIZE_CEILING = 1024 * 1024;
 
     /** Logger */
-    protected final Logger log = LoggerFactory.getLogger(getClass());
+    protected final LoggerFactory loggerFactory;
+    protected final Logger log;
 
     /** Transport layer */
     protected final Transport trans;
@@ -77,21 +77,23 @@ public abstract class AbstractChannel
 
     protected AbstractChannel(Connection conn, String type) {
         this.conn = conn;
+        this.loggerFactory = conn.getTransport().getConfig().getLoggerFactory();
         this.type = type;
+        this.log = loggerFactory.getLogger(getClass());
         this.trans = conn.getTransport();
 
         id = conn.nextID();
 
-        lwin = new Window.Local(conn.getWindowSize(), conn.getMaxPacketSize());
+        lwin = new Window.Local(conn.getWindowSize(), conn.getMaxPacketSize(), loggerFactory);
         in = new ChannelInputStream(this, trans, lwin);
 
-        openEvent = new Event<ConnectionException>("chan#" + id + " / " + "open", ConnectionException.chainer, openCloseLock);
-        closeEvent = new Event<ConnectionException>("chan#" + id + " / " + "close", ConnectionException.chainer, openCloseLock);
+        openEvent = new Event<ConnectionException>("chan#" + id + " / " + "open", ConnectionException.chainer, openCloseLock, loggerFactory);
+        closeEvent = new Event<ConnectionException>("chan#" + id + " / " + "close", ConnectionException.chainer, openCloseLock, loggerFactory);
     }
 
     protected void init(int recipient, long remoteWinSize, long remoteMaxPacketSize) {
         this.recipient = recipient;
-        rwin = new Window.Remote(remoteWinSize, (int) Math.min(remoteMaxPacketSize, REMOTE_MAX_PACKET_SIZE_CEILING));
+        rwin = new Window.Remote(remoteWinSize, (int) Math.min(remoteMaxPacketSize, REMOTE_MAX_PACKET_SIZE_CEILING), loggerFactory);
         out = new ChannelOutputStream(this, trans, rwin);
         log.debug("Initialized - {}", this);
     }
@@ -189,6 +191,11 @@ public void handle(Message msg, SSHPacket buf)
         }
     }
 
+    @Override
+    public LoggerFactory getLoggerFactory() {
+	return loggerFactory;
+    }
+
     private void gotClose()
             throws TransportException {
         log.debug("Got close");
@@ -356,7 +363,7 @@ protected Event<ConnectionException> sendChannelRequest(String reqType, boolean
             Event<ConnectionException> responseEvent = null;
             if (wantReply) {
                 responseEvent = new Event<ConnectionException>("chan#" + id + " / " + "chanreq for " + reqType,
-                                                               ConnectionException.chainer);
+                                                               ConnectionException.chainer, loggerFactory);
                 chanReqResponseEvents.add(responseEvent);
             }
             return responseEvent;
diff --git a/src/main/java/net/schmizz/sshj/connection/channel/Channel.java b/src/main/java/net/schmizz/sshj/connection/channel/Channel.java
index b13a23cad..4ad9f9759 100644
--- a/src/main/java/net/schmizz/sshj/connection/channel/Channel.java
+++ b/src/main/java/net/schmizz/sshj/connection/channel/Channel.java
@@ -16,6 +16,7 @@
 package net.schmizz.sshj.connection.channel;
 
 import net.schmizz.sshj.common.ErrorNotifiable;
+import net.schmizz.sshj.common.LoggerFactory;
 import net.schmizz.sshj.common.SSHPacketHandler;
 import net.schmizz.sshj.connection.ConnectionException;
 import net.schmizz.sshj.transport.TransportException;
@@ -134,4 +135,8 @@ void join()
     void join(long timeout, TimeUnit unit)
             throws ConnectionException;
 
+    /**
+     * Get the LoggerFactory associated with the SSH client.
+     */
+    LoggerFactory getLoggerFactory();
 }
diff --git a/src/main/java/net/schmizz/sshj/connection/channel/ChannelInputStream.java b/src/main/java/net/schmizz/sshj/connection/channel/ChannelInputStream.java
index 1839d5d2f..c48f5db25 100644
--- a/src/main/java/net/schmizz/sshj/connection/channel/ChannelInputStream.java
+++ b/src/main/java/net/schmizz/sshj/connection/channel/ChannelInputStream.java
@@ -34,7 +34,7 @@ public final class ChannelInputStream
         extends InputStream
         implements ErrorNotifiable {
 
-    private final Logger log = LoggerFactory.getLogger(getClass());
+    private final Logger log;
 
     private final Channel chan;
     private final Transport trans;
@@ -47,6 +47,7 @@ public final class ChannelInputStream
 
     public ChannelInputStream(Channel chan, Transport trans, Window.Local win) {
         this.chan = chan;
+        log = chan.getLoggerFactory().getLogger(getClass());
         this.trans = trans;
         this.win = win;
         buf = new Buffer.PlainBuffer(chan.getLocalMaxPacketSize());
diff --git a/src/main/java/net/schmizz/sshj/connection/channel/Window.java b/src/main/java/net/schmizz/sshj/connection/channel/Window.java
index 12309032f..b960b6085 100644
--- a/src/main/java/net/schmizz/sshj/connection/channel/Window.java
+++ b/src/main/java/net/schmizz/sshj/connection/channel/Window.java
@@ -15,14 +15,14 @@
  */
 package net.schmizz.sshj.connection.channel;
 
+import net.schmizz.sshj.common.LoggerFactory;
 import net.schmizz.sshj.common.SSHRuntimeException;
 import net.schmizz.sshj.connection.ConnectionException;
 import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 
 public abstract class Window {
 
-    protected final Logger log = LoggerFactory.getLogger(getClass());
+    protected final Logger log;
 
     protected final Object lock = new Object();
 
@@ -30,9 +30,10 @@ public abstract class Window {
 
     protected long size;
 
-    public Window(long initialWinSize, int maxPacketSize) {
+    public Window(long initialWinSize, int maxPacketSize, LoggerFactory loggerFactory) {
         size = initialWinSize;
         this.maxPacketSize = maxPacketSize;
+        log = loggerFactory.getLogger(getClass());
     }
 
     public void expand(long inc) {
@@ -72,8 +73,8 @@ public String toString() {
     public static final class Remote
             extends Window {
 
-        public Remote(long initialWinSize, int maxPacketSize) {
-            super(initialWinSize, maxPacketSize);
+        public Remote(long initialWinSize, int maxPacketSize, LoggerFactory loggerFactory) {
+            super(initialWinSize, maxPacketSize, loggerFactory);
         }
 
         public long awaitExpansion(long was)
@@ -108,8 +109,8 @@ public static final class Local
         private final long initialSize;
         private final long threshold;
 
-        public Local(long initialWinSize, int maxPacketSize) {
-            super(initialWinSize, maxPacketSize);
+        public Local(long initialWinSize, int maxPacketSize, LoggerFactory loggerFactory) {
+            super(initialWinSize, maxPacketSize, loggerFactory);
             this.initialSize = initialWinSize;
             threshold = Math.min(maxPacketSize * 20, initialSize / 4);
         }
diff --git a/src/main/java/net/schmizz/sshj/connection/channel/direct/AbstractDirectChannel.java b/src/main/java/net/schmizz/sshj/connection/channel/direct/AbstractDirectChannel.java
index 10595bd71..b2b4e5d66 100644
--- a/src/main/java/net/schmizz/sshj/connection/channel/direct/AbstractDirectChannel.java
+++ b/src/main/java/net/schmizz/sshj/connection/channel/direct/AbstractDirectChannel.java
@@ -16,6 +16,7 @@
 package net.schmizz.sshj.connection.channel.direct;
 
 import net.schmizz.sshj.common.Buffer;
+import net.schmizz.sshj.common.LoggerFactory;
 import net.schmizz.sshj.common.Message;
 import net.schmizz.sshj.common.SSHPacket;
 import net.schmizz.sshj.connection.Connection;
@@ -94,4 +95,4 @@ protected void gotUnknown(Message cmd, SSHPacket buf)
         }
     }
 
-}
\ No newline at end of file
+}
diff --git a/src/main/java/net/schmizz/sshj/connection/channel/direct/LocalPortForwarder.java b/src/main/java/net/schmizz/sshj/connection/channel/direct/LocalPortForwarder.java
index 9abdb6f3a..2369a6588 100644
--- a/src/main/java/net/schmizz/sshj/connection/channel/direct/LocalPortForwarder.java
+++ b/src/main/java/net/schmizz/sshj/connection/channel/direct/LocalPortForwarder.java
@@ -17,12 +17,12 @@
 
 import net.schmizz.concurrent.Event;
 import net.schmizz.sshj.common.IOUtils;
+import net.schmizz.sshj.common.LoggerFactory;
 import net.schmizz.sshj.common.SSHPacket;
 import net.schmizz.sshj.common.StreamCopier;
 import net.schmizz.sshj.connection.Connection;
 import net.schmizz.sshj.connection.channel.SocketStreamCopyMonitor;
 import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 
 import java.io.IOException;
 import java.net.ServerSocket;
@@ -82,10 +82,10 @@ protected void start()
                 throws IOException {
             socket.setSendBufferSize(getLocalMaxPacketSize());
             socket.setReceiveBufferSize(getRemoteMaxPacketSize());
-            final Event<IOException> soc2chan = new StreamCopier(socket.getInputStream(), getOutputStream())
+            final Event<IOException> soc2chan = new StreamCopier(socket.getInputStream(), getOutputStream(), loggerFactory)
                     .bufSize(getRemoteMaxPacketSize())
                     .spawnDaemon("soc2chan");
-            final Event<IOException> chan2soc = new StreamCopier(getInputStream(), socket.getOutputStream())
+            final Event<IOException> chan2soc = new StreamCopier(getInputStream(), socket.getOutputStream(), loggerFactory)
                     .bufSize(getLocalMaxPacketSize())
                     .spawnDaemon("chan2soc");
             SocketStreamCopyMonitor.monitor(5, TimeUnit.SECONDS, soc2chan, chan2soc, this, socket);
@@ -102,16 +102,18 @@ protected SSHPacket buildOpenReq() {
 
     }
 
-    private final Logger log = LoggerFactory.getLogger(LocalPortForwarder.class);
-
+    private final LoggerFactory loggerFactory;
+    private final Logger log;
     private final Connection conn;
     private final Parameters parameters;
     private final ServerSocket serverSocket;
 
-    public LocalPortForwarder(Connection conn, Parameters parameters, ServerSocket serverSocket) {
+    public LocalPortForwarder(Connection conn, Parameters parameters, ServerSocket serverSocket, LoggerFactory loggerFactory) {
         this.conn = conn;
         this.parameters = parameters;
         this.serverSocket = serverSocket;
+        this.loggerFactory = loggerFactory;
+        this.log = loggerFactory.getLogger(getClass());
     }
 
     private void startChannel(Socket socket) throws IOException {
diff --git a/src/main/java/net/schmizz/sshj/connection/channel/forwarded/AbstractForwardedChannel.java b/src/main/java/net/schmizz/sshj/connection/channel/forwarded/AbstractForwardedChannel.java
index dbf23b0fd..3eb88b5f2 100644
--- a/src/main/java/net/schmizz/sshj/connection/channel/forwarded/AbstractForwardedChannel.java
+++ b/src/main/java/net/schmizz/sshj/connection/channel/forwarded/AbstractForwardedChannel.java
@@ -73,4 +73,4 @@ public int getOriginatorPort() {
         return origPort;
     }
 
-}
\ No newline at end of file
+}
diff --git a/src/main/java/net/schmizz/sshj/connection/channel/forwarded/AbstractForwardedChannelOpener.java b/src/main/java/net/schmizz/sshj/connection/channel/forwarded/AbstractForwardedChannelOpener.java
index e8679584f..d79835eea 100644
--- a/src/main/java/net/schmizz/sshj/connection/channel/forwarded/AbstractForwardedChannelOpener.java
+++ b/src/main/java/net/schmizz/sshj/connection/channel/forwarded/AbstractForwardedChannelOpener.java
@@ -29,14 +29,14 @@
 public abstract class AbstractForwardedChannelOpener
         implements ForwardedChannelOpener {
 
-    protected final Logger log = LoggerFactory.getLogger(getClass());
-
+    protected final Logger log;
     protected final String chanType;
     protected final Connection conn;
 
     protected AbstractForwardedChannelOpener(String chanType, Connection conn) {
         this.chanType = chanType;
         this.conn = conn;
+        log = conn.getTransport().getConfig().getLoggerFactory().getLogger(getClass());
     }
 
     @Override
@@ -72,4 +72,4 @@ public void run() {
         }.start();
     }
 
-}
\ No newline at end of file
+}
diff --git a/src/main/java/net/schmizz/sshj/connection/channel/forwarded/SocketForwardingConnectListener.java b/src/main/java/net/schmizz/sshj/connection/channel/forwarded/SocketForwardingConnectListener.java
index 255902d6f..bb5fb9213 100644
--- a/src/main/java/net/schmizz/sshj/connection/channel/forwarded/SocketForwardingConnectListener.java
+++ b/src/main/java/net/schmizz/sshj/connection/channel/forwarded/SocketForwardingConnectListener.java
@@ -19,8 +19,6 @@
 import net.schmizz.sshj.common.StreamCopier;
 import net.schmizz.sshj.connection.channel.Channel;
 import net.schmizz.sshj.connection.channel.SocketStreamCopyMonitor;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 
 import java.io.IOException;
 import java.net.Socket;
@@ -31,8 +29,6 @@
 public class SocketForwardingConnectListener
         implements ConnectListener {
 
-    protected final Logger log = LoggerFactory.getLogger(getClass());
-
     protected final SocketAddress addr;
 
     /** Create with a {@link SocketAddress} this listener will forward to. */
@@ -44,7 +40,7 @@ public SocketForwardingConnectListener(SocketAddress addr) {
     @Override
     public void gotConnect(Channel.Forwarded chan)
             throws IOException {
-        log.debug("New connection from {}:{}", chan.getOriginatorIP(), chan.getOriginatorPort());
+        chan.getLoggerFactory().getLogger(getClass()).debug("New connection from {}:{}", chan.getOriginatorIP(), chan.getOriginatorPort());
 
         final Socket sock = new Socket();
         sock.setSendBufferSize(chan.getLocalMaxPacketSize());
@@ -55,11 +51,11 @@ public void gotConnect(Channel.Forwarded chan)
         // ok so far -- could connect, let's confirm the channel
         chan.confirm();
 
-        final Event<IOException> soc2chan = new StreamCopier(sock.getInputStream(), chan.getOutputStream())
+        final Event<IOException> soc2chan = new StreamCopier(sock.getInputStream(), chan.getOutputStream(), chan.getLoggerFactory())
                 .bufSize(chan.getRemoteMaxPacketSize())
                 .spawnDaemon("soc2chan");
 
-        final Event<IOException> chan2soc = new StreamCopier(chan.getInputStream(), sock.getOutputStream())
+        final Event<IOException> chan2soc = new StreamCopier(chan.getInputStream(), sock.getOutputStream(), chan.getLoggerFactory())
                 .bufSize(chan.getLocalMaxPacketSize())
                 .spawnDaemon("chan2soc");
 
diff --git a/src/main/java/net/schmizz/sshj/sftp/PacketReader.java b/src/main/java/net/schmizz/sshj/sftp/PacketReader.java
index a671db75e..5dc29a33d 100644
--- a/src/main/java/net/schmizz/sshj/sftp/PacketReader.java
+++ b/src/main/java/net/schmizz/sshj/sftp/PacketReader.java
@@ -29,7 +29,7 @@ public class PacketReader
         extends Thread {
 
     /** Logger */
-    private final Logger log = LoggerFactory.getLogger(getClass());
+    private final Logger log;
 
     private final InputStream in;
     private final Map<Long, Promise<Response, SFTPException>> promises = new ConcurrentHashMap<Long, Promise<Response, SFTPException>>();
@@ -39,6 +39,7 @@ public class PacketReader
 
     public PacketReader(SFTPEngine engine) {
         this.engine = engine;
+        log = engine.getLoggerFactory().getLogger(getClass());
         this.in = engine.getSubsystem().getInputStream();
         setName("sftp reader");
     }
@@ -106,7 +107,7 @@ public void handle()
 
     public Promise<Response, SFTPException> expectResponseTo(long requestId) {
         final Promise<Response, SFTPException> promise
-                = new Promise<Response, SFTPException>("sftp / " + requestId, SFTPException.chainer);
+                = new Promise<Response, SFTPException>("sftp / " + requestId, SFTPException.chainer, engine.getLoggerFactory());
         promises.put(requestId, promise);
         return promise;
     }
diff --git a/src/main/java/net/schmizz/sshj/sftp/RemoteDirectory.java b/src/main/java/net/schmizz/sshj/sftp/RemoteDirectory.java
index fa6b23c57..945918b73 100644
--- a/src/main/java/net/schmizz/sshj/sftp/RemoteDirectory.java
+++ b/src/main/java/net/schmizz/sshj/sftp/RemoteDirectory.java
@@ -25,7 +25,7 @@
 public class RemoteDirectory
         extends RemoteResource {
 
-    public RemoteDirectory(Requester requester, String path, byte[] handle) {
+    public RemoteDirectory(SFTPEngine requester, String path, byte[] handle) {
         super(requester, path, handle);
     }
 
diff --git a/src/main/java/net/schmizz/sshj/sftp/RemoteFile.java b/src/main/java/net/schmizz/sshj/sftp/RemoteFile.java
index a2e8eb8bf..24043c214 100644
--- a/src/main/java/net/schmizz/sshj/sftp/RemoteFile.java
+++ b/src/main/java/net/schmizz/sshj/sftp/RemoteFile.java
@@ -30,7 +30,7 @@
 public class RemoteFile
         extends RemoteResource {
 
-    public RemoteFile(Requester requester, String path, byte[] handle) {
+    public RemoteFile(SFTPEngine requester, String path, byte[] handle) {
         super(requester, path, handle);
     }
 
diff --git a/src/main/java/net/schmizz/sshj/sftp/RemoteResource.java b/src/main/java/net/schmizz/sshj/sftp/RemoteResource.java
index a71213e04..cdcbb8dba 100644
--- a/src/main/java/net/schmizz/sshj/sftp/RemoteResource.java
+++ b/src/main/java/net/schmizz/sshj/sftp/RemoteResource.java
@@ -26,14 +26,15 @@ public abstract class RemoteResource
         implements Closeable {
 
     /** Logger */
-    protected final Logger log = LoggerFactory.getLogger(getClass());
+    protected final Logger log;
 
-    protected final Requester requester;
+    protected final SFTPEngine requester;
     protected final String path;
     protected final byte[] handle;
 
-    protected RemoteResource(Requester requester, String path, byte[] handle) {
+    protected RemoteResource(SFTPEngine requester, String path, byte[] handle) {
         this.requester = requester;
+        log = requester.getLoggerFactory().getLogger(getClass());
         this.path = path;
         this.handle = handle;
     }
diff --git a/src/main/java/net/schmizz/sshj/sftp/SFTPClient.java b/src/main/java/net/schmizz/sshj/sftp/SFTPClient.java
index 8ebe17765..a8539318d 100644
--- a/src/main/java/net/schmizz/sshj/sftp/SFTPClient.java
+++ b/src/main/java/net/schmizz/sshj/sftp/SFTPClient.java
@@ -29,13 +29,14 @@ public class SFTPClient
         implements Closeable {
 
     /** Logger */
-    protected final Logger log = LoggerFactory.getLogger(getClass());
+    protected final Logger log;
 
     protected final SFTPEngine engine;
     protected final SFTPFileTransfer xfer;
 
     public SFTPClient(SFTPEngine engine) {
         this.engine = engine;
+        log = engine.getLoggerFactory().getLogger(getClass());
         this.xfer = new SFTPFileTransfer(engine);
     }
 
diff --git a/src/main/java/net/schmizz/sshj/sftp/SFTPEngine.java b/src/main/java/net/schmizz/sshj/sftp/SFTPEngine.java
index 40a9debe7..40a18c7d2 100644
--- a/src/main/java/net/schmizz/sshj/sftp/SFTPEngine.java
+++ b/src/main/java/net/schmizz/sshj/sftp/SFTPEngine.java
@@ -16,11 +16,11 @@
 package net.schmizz.sshj.sftp;
 
 import net.schmizz.concurrent.Promise;
+import net.schmizz.sshj.common.LoggerFactory;
 import net.schmizz.sshj.common.SSHException;
-import net.schmizz.sshj.connection.channel.direct.Session.Subsystem;
+import net.schmizz.sshj.connection.channel.direct.Session;
 import net.schmizz.sshj.connection.channel.direct.SessionFactory;
 import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 
 import java.io.Closeable;
 import java.io.IOException;
@@ -38,13 +38,14 @@ public class SFTPEngine
     public static final int DEFAULT_TIMEOUT_MS = 30 * 1000; // way too long, but it was the original default
 
     /** Logger */
-    protected final Logger log = LoggerFactory.getLogger(getClass());
+    protected final LoggerFactory loggerFactory;
+    protected final Logger log;
 
     protected volatile int timeoutMs = DEFAULT_TIMEOUT_MS;
 
     protected final PathHelper pathHelper;
 
-    protected final Subsystem sub;
+    protected final Session.Subsystem sub;
     protected final PacketReader reader;
     protected final OutputStream out;
 
@@ -59,7 +60,10 @@ public SFTPEngine(SessionFactory ssh)
 
     public SFTPEngine(SessionFactory ssh, String pathSep)
             throws SSHException {
-        sub = ssh.startSession().startSubsystem("sftp");
+        Session session = ssh.startSession();
+        loggerFactory = session.getLoggerFactory();
+        log = loggerFactory.getLogger(getClass());
+        sub = session.startSubsystem("sftp");
         out = sub.getOutputStream();
         reader = new PacketReader(this);
         pathHelper = new PathHelper(new PathHelper.Canonicalizer() {
@@ -94,7 +98,7 @@ public SFTPEngine init()
         return this;
     }
 
-    public Subsystem getSubsystem() {
+    public Session.Subsystem getSubsystem() {
         return sub;
     }
 
@@ -248,6 +252,10 @@ public void close()
         reader.interrupt();
     }
 
+    protected LoggerFactory getLoggerFactory() {
+	return loggerFactory;
+    }
+
     protected FileAttributes stat(PacketType pt, String path)
             throws IOException {
         return doRequest(newRequest(pt).putString(path))
diff --git a/src/main/java/net/schmizz/sshj/sftp/SFTPFileTransfer.java b/src/main/java/net/schmizz/sshj/sftp/SFTPFileTransfer.java
index 0af1a12e9..f23314e93 100644
--- a/src/main/java/net/schmizz/sshj/sftp/SFTPFileTransfer.java
+++ b/src/main/java/net/schmizz/sshj/sftp/SFTPFileTransfer.java
@@ -35,6 +35,7 @@ public class SFTPFileTransfer
     private volatile boolean preserveAttributes = true;
 
     public SFTPFileTransfer(SFTPEngine engine) {
+	super(engine.getLoggerFactory());
         this.engine = engine;
     }
 
@@ -138,7 +139,7 @@ private LocalDestFile downloadFile(final StreamCopier.Listener listener,
                 final RemoteFile.ReadAheadRemoteFileInputStream rfis = rf.new ReadAheadRemoteFileInputStream(16);
                 final OutputStream os = adjusted.getOutputStream();
                 try {
-                    new StreamCopier(rfis, os)
+                    new StreamCopier(rfis, os, engine.getLoggerFactory())
                             .bufSize(engine.getSubsystem().getLocalMaxPacketSize())
                             .keepFlushing(false)
                             .listener(listener)
@@ -231,7 +232,7 @@ private String uploadFile(final StreamCopier.Listener listener,
             try (RemoteFile rf = engine.open(adjusted, EnumSet.of(OpenMode.WRITE, OpenMode.CREAT, OpenMode.TRUNC))) {
                 try (InputStream fis = local.getInputStream();
                      RemoteFile.RemoteFileOutputStream rfos = rf.new RemoteFileOutputStream(0, 16)) {
-                    new StreamCopier(fis, rfos)
+                    new StreamCopier(fis, rfos, engine.getLoggerFactory())
                             .bufSize(engine.getSubsystem().getRemoteMaxPacketSize() - rf.getOutgoingPacketOverhead())
                             .keepFlushing(false)
                             .listener(listener)
diff --git a/src/main/java/net/schmizz/sshj/transport/Decoder.java b/src/main/java/net/schmizz/sshj/transport/Decoder.java
index 5cdb15642..bfb48b484 100644
--- a/src/main/java/net/schmizz/sshj/transport/Decoder.java
+++ b/src/main/java/net/schmizz/sshj/transport/Decoder.java
@@ -16,6 +16,7 @@
 package net.schmizz.sshj.transport;
 
 import net.schmizz.sshj.common.*;
+import net.schmizz.sshj.transport.Transport;
 import net.schmizz.sshj.transport.cipher.Cipher;
 import net.schmizz.sshj.transport.compression.Compression;
 import net.schmizz.sshj.transport.mac.MAC;
@@ -28,7 +29,7 @@ final class Decoder
 
     private static final int MAX_PACKET_LEN = 256 * 1024;
 
-    private final Logger log = LoggerFactory.getLogger(getClass());
+    private final Logger log;
 
     /** What we pass decoded packets to */
     private final SSHPacketHandler packetHandler;
@@ -48,8 +49,9 @@ final class Decoder
      */
     private int needed = 8;
 
-    Decoder(SSHPacketHandler packetHandler) {
+    Decoder(Transport packetHandler) {
         this.packetHandler = packetHandler;
+        log = packetHandler.getConfig().getLoggerFactory().getLogger(getClass());
     }
 
     /**
diff --git a/src/main/java/net/schmizz/sshj/transport/Encoder.java b/src/main/java/net/schmizz/sshj/transport/Encoder.java
index c89d7542f..58bd58003 100644
--- a/src/main/java/net/schmizz/sshj/transport/Encoder.java
+++ b/src/main/java/net/schmizz/sshj/transport/Encoder.java
@@ -15,13 +15,13 @@
  */
 package net.schmizz.sshj.transport;
 
+import net.schmizz.sshj.common.LoggerFactory;
 import net.schmizz.sshj.common.SSHPacket;
 import net.schmizz.sshj.transport.cipher.Cipher;
 import net.schmizz.sshj.transport.compression.Compression;
 import net.schmizz.sshj.transport.mac.MAC;
 import net.schmizz.sshj.transport.random.Random;
 import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 
 import java.util.concurrent.locks.Lock;
 
@@ -29,15 +29,14 @@
 final class Encoder
         extends Converter {
 
-    private final Logger log = LoggerFactory.getLogger(getClass());
-
+    private final Logger log;
     private final Random prng;
-
     private final Lock encodeLock;
 
-    Encoder(Random prng, Lock encodeLock) {
+    Encoder(Random prng, Lock encodeLock, LoggerFactory loggerFactory) {
         this.prng = prng;
         this.encodeLock = encodeLock;
+        log = loggerFactory.getLogger(getClass());
     }
 
     private SSHPacket checkHeaderSpace(SSHPacket buffer) {
@@ -142,4 +141,4 @@ Compression.Mode getCompressionType() {
         return Compression.Mode.DEFLATE;
     }
 
-}
\ No newline at end of file
+}
diff --git a/src/main/java/net/schmizz/sshj/transport/KeyExchanger.java b/src/main/java/net/schmizz/sshj/transport/KeyExchanger.java
index 33f0422c7..998b0c802 100644
--- a/src/main/java/net/schmizz/sshj/transport/KeyExchanger.java
+++ b/src/main/java/net/schmizz/sshj/transport/KeyExchanger.java
@@ -50,8 +50,7 @@ private static enum Expected {
         NEWKEYS,
     }
 
-    private final Logger log = LoggerFactory.getLogger(getClass());
-
+    private final Logger log;
     private final TransportImpl transport;
 
     /**
@@ -76,18 +75,20 @@ private static enum Expected {
     private Proposal clientProposal;
     private NegotiatedAlgorithms negotiatedAlgs;
 
-    private final Event<TransportException> kexInitSent =
-            new Event<TransportException>("kexinit sent", TransportException.chainer);
+    private final Event<TransportException> kexInitSent;
 
     private final Event<TransportException> done;
 
     KeyExchanger(TransportImpl trans) {
         this.transport = trans;
+        log = trans.getConfig().getLoggerFactory().getLogger(getClass());
+        kexInitSent = new Event<TransportException>("kexinit sent", TransportException.chainer, trans.getConfig().getLoggerFactory());
+
         /*
          * Use TransportImpl's writeLock, since TransportImpl.write() may wait on this event and the lock should
          * be released while waiting.
          */
-        this.done = new Event<TransportException>("kex done", TransportException.chainer, trans.getWriteLock());
+        this.done = new Event<TransportException>("kex done", TransportException.chainer, trans.getWriteLock(), trans.getConfig().getLoggerFactory());
     }
 
     /**
diff --git a/src/main/java/net/schmizz/sshj/transport/Reader.java b/src/main/java/net/schmizz/sshj/transport/Reader.java
index aa6c4a71d..30b4e8b85 100644
--- a/src/main/java/net/schmizz/sshj/transport/Reader.java
+++ b/src/main/java/net/schmizz/sshj/transport/Reader.java
@@ -24,12 +24,12 @@
 public final class Reader
         extends Thread {
 
-    private final Logger log = LoggerFactory.getLogger(getClass());
-
+    private final Logger log;
     private final TransportImpl trans;
 
     public Reader(TransportImpl trans) {
         this.trans = trans;
+        log = trans.getConfig().getLoggerFactory().getLogger(getClass());
         setName("reader");
     }
 
diff --git a/src/main/java/net/schmizz/sshj/transport/Transport.java b/src/main/java/net/schmizz/sshj/transport/Transport.java
index ab043ad32..d6ed7116d 100644
--- a/src/main/java/net/schmizz/sshj/transport/Transport.java
+++ b/src/main/java/net/schmizz/sshj/transport/Transport.java
@@ -18,6 +18,7 @@
 import net.schmizz.sshj.Config;
 import net.schmizz.sshj.Service;
 import net.schmizz.sshj.common.DisconnectReason;
+import net.schmizz.sshj.common.LoggerFactory;
 import net.schmizz.sshj.common.SSHPacket;
 import net.schmizz.sshj.common.SSHPacketHandler;
 import net.schmizz.sshj.transport.verification.AlgorithmsVerifier;
@@ -235,4 +236,4 @@ long write(SSHPacket payload)
      * @param e The exception that occurred.
      */
     void die(Exception e);
-}
\ No newline at end of file
+}
diff --git a/src/main/java/net/schmizz/sshj/transport/TransportImpl.java b/src/main/java/net/schmizz/sshj/transport/TransportImpl.java
index fd3a51457..561b6ea63 100644
--- a/src/main/java/net/schmizz/sshj/transport/TransportImpl.java
+++ b/src/main/java/net/schmizz/sshj/transport/TransportImpl.java
@@ -26,7 +26,6 @@
 import net.schmizz.sshj.transport.verification.AlgorithmsVerifier;
 import net.schmizz.sshj.transport.verification.HostKeyVerifier;
 import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 
 import java.io.IOException;
 import java.io.InputStream;
@@ -36,7 +35,7 @@
 
 /** A thread-safe {@link Transport} implementation. */
 public final class TransportImpl
-        implements Transport {
+        implements Transport, DisconnectListener {
 
     private static final class NullService
             extends AbstractService {
@@ -46,6 +45,7 @@ private static final class NullService
         }
 
     }
+
     static final class ConnInfo {
 
         final String host;
@@ -61,16 +61,12 @@ public ConnInfo(String host, int port, InputStream in, OutputStream out) {
         }
 
     }
-    private final Logger log = LoggerFactory.getLogger(getClass());
 
-    private final Service nullService = new NullService(this);
+    private final LoggerFactory loggerFactory;
 
-    private final DisconnectListener nullDisconnectListener = new DisconnectListener() {
-        @Override
-        public void notifyDisconnect(DisconnectReason reason, String message) {
-            log.info("Disconnected - {}", reason);
-        }
-    };
+    private final Logger log;
+
+    private final Service nullService;
 
     private final Config config;
 
@@ -88,9 +84,9 @@ public void notifyDisconnect(DisconnectReason reason, String message) {
 
     private final Decoder decoder;
 
-    private final Event<TransportException> serviceAccept = new Event<TransportException>("service accept", TransportException.chainer);
+    private final Event<TransportException> serviceAccept;
 
-    private final Event<TransportException> close = new Event<TransportException>("transport close", TransportException.chainer);
+    private final Event<TransportException> close;
 
     /** Client version identification string */
     private final String clientID;
@@ -100,9 +96,9 @@ public void notifyDisconnect(DisconnectReason reason, String message) {
     private volatile boolean authed = false;
 
     /** Currently active service e.g. UserAuthService, ConnectionService */
-    private volatile Service service = nullService;
+    private volatile Service service;
 
-    private DisconnectListener disconnectListener = nullDisconnectListener;
+    private DisconnectListener disconnectListener;
 
     private ConnInfo connInfo;
 
@@ -116,8 +112,15 @@ public void notifyDisconnect(DisconnectReason reason, String message) {
 
     public TransportImpl(Config config) {
         this.config = config;
+        this.loggerFactory = config.getLoggerFactory();
+        this.serviceAccept = new Event<TransportException>("service accept", TransportException.chainer, loggerFactory);
+        this.close = new Event<TransportException>("transport close", TransportException.chainer, loggerFactory);
+        this.nullService  = new NullService(this);
+        this.service = nullService;
+	this.log = loggerFactory.getLogger(getClass());
+        this.disconnectListener = this;
         this.reader = new Reader(this);
-        this.encoder = new Encoder(config.getRandomFactory().create(), writeLock);
+        this.encoder = new Encoder(config.getRandomFactory().create(), writeLock, loggerFactory);
         this.decoder = new Decoder(this);
         this.kexer = new KeyExchanger(this);
         this.clientID = String.format("SSH-2.0-%s", config.getVersion());
@@ -131,16 +134,21 @@ public TransportImpl(Config config) {
     @Deprecated
     public TransportImpl(Config config, SSHClient sshClient) {
         this.config = config;
+        this.loggerFactory = config.getLoggerFactory();
+        this.serviceAccept = new Event<TransportException>("service accept", TransportException.chainer, loggerFactory);
+        this.close = new Event<TransportException>("transport close", TransportException.chainer, loggerFactory);
+        this.log = loggerFactory.getLogger(getClass());
+        this.nullService  = new NullService(this);
+        this.service = nullService;
+        this.disconnectListener = this;
         this.reader = new Reader(this);
-        this.encoder = new Encoder(config.getRandomFactory().create(), writeLock);
+        this.encoder = new Encoder(config.getRandomFactory().create(), writeLock, loggerFactory);
         this.decoder = new Decoder(this);
         this.kexer = new KeyExchanger(this);
         this.clientID = String.format("SSH-2.0-%s", config.getVersion());
         this.sshClient = sshClient;
     }
 
-
-
     @Override
     public void init(String remoteHost, int remotePort, InputStream in, OutputStream out)
             throws TransportException {
@@ -166,6 +174,14 @@ public void init(String remoteHost, int remotePort, InputStream in, OutputStream
         reader.start();
     }
 
+    /**
+     * TransportImpl implements its own default DisconnectListener.
+     */
+    @Override
+    public void notifyDisconnect(DisconnectReason reason, String message) {
+        log.info("Disconnected - {}", reason);
+    }
+
     private void receiveServerIdent() throws IOException {
         final Buffer.PlainBuffer buf = new Buffer.PlainBuffer();
         while ((serverID = readIdentification(buf)).isEmpty()) {
@@ -203,7 +219,7 @@ private void sendClientIdent() throws IOException {
      */
     private String readIdentification(Buffer.PlainBuffer buffer)
             throws IOException {
-        String ident = new IdentificationStringParser(buffer).parseIdentificationString();
+        String ident = new IdentificationStringParser(loggerFactory, buffer).parseIdentificationString();
         if (ident.isEmpty()) {
             return ident;
         }
@@ -432,7 +448,7 @@ public void disconnect(DisconnectReason reason, String message) {
 
     @Override
     public void setDisconnectListener(DisconnectListener listener) {
-        this.disconnectListener = listener == null ? nullDisconnectListener : listener;
+        this.disconnectListener = listener == null ? this : listener;
     }
 
     @Override
diff --git a/src/main/java/net/schmizz/sshj/transport/verification/OpenSSHKnownHosts.java b/src/main/java/net/schmizz/sshj/transport/verification/OpenSSHKnownHosts.java
index 1a0204a6a..dbd23affa 100644
--- a/src/main/java/net/schmizz/sshj/transport/verification/OpenSSHKnownHosts.java
+++ b/src/main/java/net/schmizz/sshj/transport/verification/OpenSSHKnownHosts.java
@@ -19,7 +19,6 @@
 import net.schmizz.sshj.transport.mac.HMACSHA1;
 import net.schmizz.sshj.transport.mac.MAC;
 import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 
 import java.io.*;
 import java.math.BigInteger;
@@ -38,23 +37,29 @@
 public class OpenSSHKnownHosts
         implements HostKeyVerifier {
 
-    private static final Logger LOG = LoggerFactory.getLogger(OpenSSHKnownHosts.class);
-    protected final Logger log = LoggerFactory.getLogger(getClass());
+    protected final Logger log;
 
     protected final File khFile;
     protected final List<HostEntry> entries = new ArrayList<HostEntry>();
 
     public OpenSSHKnownHosts(File khFile)
             throws IOException {
+        this(khFile, LoggerFactory.DEFAULT);
+    }
+
+    public OpenSSHKnownHosts(File khFile, LoggerFactory loggerFactory)
+            throws IOException {
         this.khFile = khFile;
+        log = loggerFactory.getLogger(getClass());
         if (khFile.exists()) {
+            final EntryFactory entryFactory = new EntryFactory();
             final BufferedReader br = new BufferedReader(new FileReader(khFile));
             try {
                 // Read in the file, storing each line as an entry
                 String line;
                 while ((line = br.readLine()) != null)
                     try {
-                        HostEntry entry = EntryFactory.parseEntry(line);
+                        HostEntry entry = entryFactory.parseEntry(line);
                         if (entry != null) {
                             entries.add(entry);
                         }
@@ -173,9 +178,11 @@ public static File detectSSHDir() {
      * <p/>
      * Lines starting with `#' and empty lines are ignored as comments.
      */
-    public static class EntryFactory {
+    public class EntryFactory {
+        EntryFactory() {
+        }
 
-        public static HostEntry parseEntry(String line)
+        public HostEntry parseEntry(String line)
                 throws IOException {
             if (isComment(line)) {
                 return new CommentEntry(line);
@@ -189,7 +196,7 @@ public static HostEntry parseEntry(String line)
                 i++;
             }
             if(split.length < 3) {
-                LOG.error("Error reading entry `{}`", line);
+                log.error("Error reading entry `{}`", line);
                 return null;
             }
             final String hostnames = split[i++];
@@ -210,11 +217,11 @@ public static HostEntry parseEntry(String line)
                     final KeyFactory keyFactory = SecurityUtils.getKeyFactory("RSA");
                     key = keyFactory.generatePublic(new RSAPublicKeySpec(n, e));
                 } catch (Exception ex) {
-                    LOG.error("Error reading entry `{}`, could not create key", line, ex);
+                    log.error("Error reading entry `{}`, could not create key", line, ex);
                     return null;
                 }
             } else {
-                LOG.error("Error reading entry `{}`, could not determine type", line);
+                log.error("Error reading entry `{}`, could not determine type", line);
                 return null;
             }
 
@@ -225,12 +232,12 @@ public static HostEntry parseEntry(String line)
             }
         }
 
-        private static PublicKey getKey(String sKey)
+        private PublicKey getKey(String sKey)
                 throws IOException {
             return new Buffer.PlainBuffer(Base64.decode(sKey)).readPublicKey();
         }
 
-        private static boolean isBits(String type) {
+        private boolean isBits(String type) {
             try {
                 Integer.parseInt(type);
                 return true;
@@ -239,23 +246,23 @@ private static boolean isBits(String type) {
             }
         }
 
-        private static boolean isComment(String line) {
+        private boolean isComment(String line) {
             return line.isEmpty() || line.startsWith("#");
         }
 
-        public static boolean isHashed(String line) {
+        public boolean isHashed(String line) {
             return line.startsWith("|1|");
         }
 
     }
 
     public interface HostEntry {
-	KeyType getType();
+        KeyType getType();
 
-	String getFingerprint();
+        String getFingerprint();
 
-	boolean appliesTo(String host)
-		throws IOException;
+        boolean appliesTo(String host)
+                throws IOException;
 
         boolean appliesTo(KeyType type, String host)
                 throws IOException;
@@ -274,21 +281,21 @@ public CommentEntry(String comment) {
             this.comment = comment;
         }
 
-	@Override
-	public KeyType getType() {
-	    return KeyType.UNKNOWN;
-	}
+        @Override
+        public KeyType getType() {
+            return KeyType.UNKNOWN;
+        }
 
-	@Override
-	public String getFingerprint() {
-	    return null;
-	}
+        @Override
+        public String getFingerprint() {
+            return null;
+        }
 
-	@Override
-	public boolean appliesTo(String host)
-		throws IOException {
-	    return false;
-	}
+        @Override
+        public boolean appliesTo(String host)
+                throws IOException {
+            return false;
+        }
 
         @Override
         public boolean appliesTo(KeyType type, String host) {
@@ -319,15 +326,15 @@ public AbstractEntry(Marker marker, KeyType type, PublicKey key) {
             this.key = key;
         }
 
-	@Override
-	public KeyType getType() {
-	    return type;
-	}
+        @Override
+        public KeyType getType() {
+            return type;
+        }
 
-	@Override
-	public String getFingerprint() {
-	    return SecurityUtils.getFingerprint(key);
-	}
+        @Override
+        public String getFingerprint() {
+            return SecurityUtils.getFingerprint(key);
+        }
 
         @Override
         public boolean verify(PublicKey key)
@@ -370,11 +377,11 @@ protected String getHostPart() {
             return hostnames;
         }
 
-	@Override
-	public boolean appliesTo(String host)
-		throws IOException {
-	    return hosts.contains(host);
-	}
+        @Override
+        public boolean appliesTo(String host)
+                throws IOException {
+            return hosts.contains(host);
+        }
 
         @Override
         public boolean appliesTo(KeyType type, String host)
@@ -404,11 +411,11 @@ public HashedEntry(Marker marker, String hash, KeyType type, PublicKey key)
             }
         }
 
-	@Override
-	public boolean appliesTo(String host)
-		 throws IOException {
-	    return hashedHost.equals(hashHost(host));
-	}
+        @Override
+        public boolean appliesTo(String host)
+                 throws IOException {
+            return hashedHost.equals(hashHost(host));
+        }
 
         @Override
         public boolean appliesTo(KeyType type, String host)
diff --git a/src/main/java/net/schmizz/sshj/userauth/UserAuthImpl.java b/src/main/java/net/schmizz/sshj/userauth/UserAuthImpl.java
index d4c351afd..4171e49a6 100644
--- a/src/main/java/net/schmizz/sshj/userauth/UserAuthImpl.java
+++ b/src/main/java/net/schmizz/sshj/userauth/UserAuthImpl.java
@@ -37,8 +37,7 @@ public class UserAuthImpl
         extends AbstractService
         implements UserAuth {
 
-    private final Promise<Boolean, UserAuthException> authenticated
-            = new Promise<Boolean, UserAuthException>("authenticated", UserAuthException.chainer);
+    private final Promise<Boolean, UserAuthException> authenticated;
 
     // Externally available
     private volatile String banner = "";
@@ -51,6 +50,7 @@ public class UserAuthImpl
 
     public UserAuthImpl(Transport trans) {
         super("ssh-userauth", trans);
+        authenticated = new Promise<Boolean, UserAuthException>("authenticated", UserAuthException.chainer, trans.getConfig().getLoggerFactory());
     }
 
     @Override
diff --git a/src/main/java/net/schmizz/sshj/userauth/method/AbstractAuthMethod.java b/src/main/java/net/schmizz/sshj/userauth/method/AbstractAuthMethod.java
index 82a12c4ae..4feb290bf 100644
--- a/src/main/java/net/schmizz/sshj/userauth/method/AbstractAuthMethod.java
+++ b/src/main/java/net/schmizz/sshj/userauth/method/AbstractAuthMethod.java
@@ -15,6 +15,7 @@
  */
 package net.schmizz.sshj.userauth.method;
 
+import net.schmizz.sshj.common.LoggerFactory;
 import net.schmizz.sshj.common.Message;
 import net.schmizz.sshj.common.SSHPacket;
 import net.schmizz.sshj.transport.TransportException;
@@ -22,14 +23,13 @@
 import net.schmizz.sshj.userauth.UserAuthException;
 import net.schmizz.sshj.userauth.password.AccountResource;
 import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 
 /** This abstract class for {@link AuthMethod} implements common or default functionality. */
 public abstract class AbstractAuthMethod
         implements AuthMethod {
 
     /** Logger */
-    protected final Logger log = LoggerFactory.getLogger(getClass());
+    protected Logger log = org.slf4j.LoggerFactory.getLogger(getClass());
 
     private final String name;
 
@@ -41,6 +41,11 @@ protected AbstractAuthMethod(String name) {
         this.name = name;
     }
 
+    @Override
+    public void setLoggerFactory(LoggerFactory loggerFactory) {
+        log = loggerFactory.getLogger(getClass());
+    }
+
     @Override
     public String getName() {
         return name;
diff --git a/src/main/java/net/schmizz/sshj/userauth/method/AuthMethod.java b/src/main/java/net/schmizz/sshj/userauth/method/AuthMethod.java
index 4401fc8ba..9c0a0195f 100644
--- a/src/main/java/net/schmizz/sshj/userauth/method/AuthMethod.java
+++ b/src/main/java/net/schmizz/sshj/userauth/method/AuthMethod.java
@@ -15,6 +15,7 @@
  */
 package net.schmizz.sshj.userauth.method;
 
+import net.schmizz.sshj.common.LoggerFactory;
 import net.schmizz.sshj.common.SSHPacketHandler;
 import net.schmizz.sshj.transport.TransportException;
 import net.schmizz.sshj.userauth.AuthParams;
@@ -44,4 +45,5 @@ void request()
     /** @return whether authentication should be reattempted if it failed. */
     boolean shouldRetry();
 
+    void setLoggerFactory(LoggerFactory loggerFactory);
 }
diff --git a/src/main/java/net/schmizz/sshj/userauth/method/PasswordResponseProvider.java b/src/main/java/net/schmizz/sshj/userauth/method/PasswordResponseProvider.java
index 57bc6b8f2..d8813d9ee 100644
--- a/src/main/java/net/schmizz/sshj/userauth/method/PasswordResponseProvider.java
+++ b/src/main/java/net/schmizz/sshj/userauth/method/PasswordResponseProvider.java
@@ -15,10 +15,10 @@
  */
 package net.schmizz.sshj.userauth.method;
 
+import net.schmizz.sshj.common.LoggerFactory;
 import net.schmizz.sshj.userauth.password.PasswordFinder;
 import net.schmizz.sshj.userauth.password.Resource;
 import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 
 import java.util.Collections;
 import java.util.List;
@@ -29,12 +29,11 @@ public class PasswordResponseProvider
 
     public static final Pattern DEFAULT_PROMPT_PATTERN = Pattern.compile(".*[pP]assword:\\s?\\z", Pattern.DOTALL);
 
-    private final Logger log = LoggerFactory.getLogger(getClass());
-
     private static final char[] EMPTY_RESPONSE = new char[0];
 
     private final Pattern promptPattern;
     private final PasswordFinder pwdf;
+    private final Logger log;
 
     private Resource resource;
 
@@ -43,8 +42,13 @@ public PasswordResponseProvider(PasswordFinder pwdf) {
     }
 
     public PasswordResponseProvider(PasswordFinder pwdf, Pattern promptPattern) {
+        this(pwdf, promptPattern, LoggerFactory.DEFAULT);
+    }
+
+    public PasswordResponseProvider(PasswordFinder pwdf, Pattern promptPattern, LoggerFactory loggerFactory) {
         this.pwdf = pwdf;
         this.promptPattern = promptPattern;
+        log = loggerFactory.getLogger(getClass());
     }
 
     @Override
diff --git a/src/main/java/net/schmizz/sshj/xfer/AbstractFileTransfer.java b/src/main/java/net/schmizz/sshj/xfer/AbstractFileTransfer.java
index d6f658e08..3a59406c8 100644
--- a/src/main/java/net/schmizz/sshj/xfer/AbstractFileTransfer.java
+++ b/src/main/java/net/schmizz/sshj/xfer/AbstractFileTransfer.java
@@ -15,23 +15,32 @@
  */
 package net.schmizz.sshj.xfer;
 
+import net.schmizz.sshj.common.LoggerFactory;
+
 import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 
 public abstract class AbstractFileTransfer {
 
-    protected final Logger log = LoggerFactory.getLogger(getClass());
+    protected final LoggerFactory loggerFactory;
+    protected final Logger log;
+
+    private final LoggingTransferListener loggingTransferListener;
 
-    public static final LoggingTransferListener LOGGING_TRANSFER_LISTENER = new LoggingTransferListener();
+    private volatile TransferListener transferListener;
 
-    private volatile TransferListener transferListener = LOGGING_TRANSFER_LISTENER;
+    protected AbstractFileTransfer(LoggerFactory loggerFactory) {
+        this.loggerFactory = loggerFactory;
+        log = loggerFactory.getLogger(getClass());
+        loggingTransferListener = new LoggingTransferListener(loggerFactory);
+        transferListener = loggingTransferListener;
+    }
 
     public TransferListener getTransferListener() {
         return transferListener;
     }
 
     public void setTransferListener(TransferListener transferListener) {
-        this.transferListener = (transferListener == null) ? LOGGING_TRANSFER_LISTENER : transferListener;
+        this.transferListener = (transferListener == null) ? loggingTransferListener : transferListener;
     }
 
-}
\ No newline at end of file
+}
diff --git a/src/main/java/net/schmizz/sshj/xfer/LoggingTransferListener.java b/src/main/java/net/schmizz/sshj/xfer/LoggingTransferListener.java
index c939a764c..50798a5da 100644
--- a/src/main/java/net/schmizz/sshj/xfer/LoggingTransferListener.java
+++ b/src/main/java/net/schmizz/sshj/xfer/LoggingTransferListener.java
@@ -15,31 +15,34 @@
  */
 package net.schmizz.sshj.xfer;
 
+import net.schmizz.sshj.common.LoggerFactory;
 import net.schmizz.sshj.common.StreamCopier;
 import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 
 import java.io.IOException;
 
 public class LoggingTransferListener
         implements TransferListener {
 
-    private final Logger log = LoggerFactory.getLogger(getClass());
+    private final LoggerFactory loggerFactory;
+    private final Logger log;
 
     private final String relPath;
 
-    public LoggingTransferListener() {
-        this("");
+    public LoggingTransferListener(LoggerFactory loggerFactory) {
+        this("", loggerFactory);
     }
 
-    private LoggingTransferListener(String relPath) {
+    private LoggingTransferListener(String relPath, LoggerFactory loggerFactory) {
         this.relPath = relPath;
+        this.loggerFactory = loggerFactory;
+        log = loggerFactory.getLogger(getClass());
     }
 
     @Override
     public TransferListener directory(String name) {
         log.debug("started transferring directory `{}`", name);
-        return new LoggingTransferListener(relPath + name + "/");
+        return new LoggingTransferListener(relPath + name + "/", loggerFactory);
     }
 
     @Override
diff --git a/src/main/java/net/schmizz/sshj/xfer/scp/SCPEngine.java b/src/main/java/net/schmizz/sshj/xfer/scp/SCPEngine.java
index a3494b168..3869e1100 100644
--- a/src/main/java/net/schmizz/sshj/xfer/scp/SCPEngine.java
+++ b/src/main/java/net/schmizz/sshj/xfer/scp/SCPEngine.java
@@ -16,13 +16,13 @@
 package net.schmizz.sshj.xfer.scp;
 
 import net.schmizz.sshj.common.IOUtils;
+import net.schmizz.sshj.common.LoggerFactory;
 import net.schmizz.sshj.common.SSHException;
 import net.schmizz.sshj.common.StreamCopier;
 import net.schmizz.sshj.connection.channel.direct.Session.Command;
 import net.schmizz.sshj.connection.channel.direct.SessionFactory;
 import net.schmizz.sshj.xfer.TransferListener;
 import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 
 import java.io.ByteArrayOutputStream;
 import java.io.IOException;
@@ -35,7 +35,8 @@ class SCPEngine {
 
     private static final char LF = '\n';
 
-    private final Logger log = LoggerFactory.getLogger(getClass());
+    private final LoggerFactory loggerFactory;
+    private final Logger log;
 
     private final SessionFactory host;
     private final TransferListener listener;
@@ -43,9 +44,11 @@ class SCPEngine {
     private Command scp;
     private int exitStatus;
 
-    SCPEngine(SessionFactory host, TransferListener listener) {
+    SCPEngine(SessionFactory host, TransferListener listener, LoggerFactory loggerFactory) {
         this.host = host;
         this.listener = listener;
+        this.loggerFactory = loggerFactory;
+        log = loggerFactory.getLogger(getClass());
     }
 
     public int getExitStatus() {
@@ -57,7 +60,7 @@ void check(String what)
         int code = scp.getInputStream().read();
         switch (code) {
             case -1:
-                String stderr = IOUtils.readFully(scp.getErrorStream()).toString();
+                String stderr = IOUtils.readFully(scp.getErrorStream(), loggerFactory).toString();
                 if (!stderr.isEmpty())
                     stderr = ". Additional info: `" + stderr + "`";
                 throw new SCPException("EOF while expecting response to protocol message" + stderr);
@@ -137,7 +140,7 @@ void signal(String what) throws IOException {
     }
 
     long transferToRemote(StreamCopier.Listener listener, InputStream src, long length) throws IOException {
-        return new StreamCopier(src, scp.getOutputStream())
+        return new StreamCopier(src, scp.getOutputStream(), loggerFactory)
                 .bufSize(scp.getRemoteMaxPacketSize()).length(length)
                 .keepFlushing(false)
                 .listener(listener)
@@ -145,7 +148,7 @@ long transferToRemote(StreamCopier.Listener listener, InputStream src, long leng
     }
 
     long transferFromRemote(StreamCopier.Listener listener, OutputStream dest, long length) throws IOException {
-        return new StreamCopier(scp.getInputStream(), dest)
+        return new StreamCopier(scp.getInputStream(), dest, loggerFactory)
                 .bufSize(scp.getLocalMaxPacketSize()).length(length)
                 .keepFlushing(false)
                 .listener(listener)
diff --git a/src/main/java/net/schmizz/sshj/xfer/scp/SCPFileTransfer.java b/src/main/java/net/schmizz/sshj/xfer/scp/SCPFileTransfer.java
index 38282cfa3..e4afe6a17 100644
--- a/src/main/java/net/schmizz/sshj/xfer/scp/SCPFileTransfer.java
+++ b/src/main/java/net/schmizz/sshj/xfer/scp/SCPFileTransfer.java
@@ -15,6 +15,7 @@
  */
 package net.schmizz.sshj.xfer.scp;
 
+import net.schmizz.sshj.common.LoggerFactory;
 import net.schmizz.sshj.connection.channel.direct.SessionFactory;
 import net.schmizz.sshj.xfer.*;
 
@@ -30,7 +31,8 @@ public class SCPFileTransfer
     private final SessionFactory sessionFactory;
     private int bandwidthLimit;
 
-    public SCPFileTransfer(SessionFactory sessionFactory) {
+    public SCPFileTransfer(SessionFactory sessionFactory, LoggerFactory loggerFactory) {
+	super(loggerFactory);
         this.sessionFactory = sessionFactory;
         this.bandwidthLimit = DEFAULT_BANDWIDTH_LIMIT;
     }
@@ -44,7 +46,7 @@ public SCPUploadClient newSCPUploadClient() {
     }
 
     private SCPEngine newSCPEngine() {
-        return new SCPEngine(sessionFactory, getTransferListener());
+        return new SCPEngine(sessionFactory, getTransferListener(), loggerFactory);
     }
 
     @Override

From f63a88ec9f1ca21db2d18eb68056fcf51a107ff5 Mon Sep 17 00:00:00 2001
From: David Solin <solind@Gallifrey.local>
Date: Tue, 23 Aug 2016 19:24:11 -0500
Subject: [PATCH 2/7] Removed unnecessary import statements.

---
 src/main/java/net/schmizz/sshj/AbstractService.java              | 1 -
 src/main/java/net/schmizz/sshj/connection/Connection.java        | 1 -
 .../sshj/connection/channel/direct/AbstractDirectChannel.java    | 1 -
 src/main/java/net/schmizz/sshj/transport/Transport.java          | 1 -
 4 files changed, 4 deletions(-)

diff --git a/src/main/java/net/schmizz/sshj/AbstractService.java b/src/main/java/net/schmizz/sshj/AbstractService.java
index 2eb4b615f..a57ea3762 100644
--- a/src/main/java/net/schmizz/sshj/AbstractService.java
+++ b/src/main/java/net/schmizz/sshj/AbstractService.java
@@ -16,7 +16,6 @@
 package net.schmizz.sshj;
 
 import net.schmizz.sshj.common.DisconnectReason;
-import net.schmizz.sshj.common.LoggerFactory;
 import net.schmizz.sshj.common.Message;
 import net.schmizz.sshj.common.SSHException;
 import net.schmizz.sshj.common.SSHPacket;
diff --git a/src/main/java/net/schmizz/sshj/connection/Connection.java b/src/main/java/net/schmizz/sshj/connection/Connection.java
index d08bb4ae2..0510b590c 100644
--- a/src/main/java/net/schmizz/sshj/connection/Connection.java
+++ b/src/main/java/net/schmizz/sshj/connection/Connection.java
@@ -17,7 +17,6 @@
 
 import net.schmizz.concurrent.Promise;
 import net.schmizz.keepalive.KeepAlive;
-import net.schmizz.sshj.common.LoggerFactory;
 import net.schmizz.sshj.common.SSHPacket;
 import net.schmizz.sshj.connection.channel.Channel;
 import net.schmizz.sshj.connection.channel.OpenFailException;
diff --git a/src/main/java/net/schmizz/sshj/connection/channel/direct/AbstractDirectChannel.java b/src/main/java/net/schmizz/sshj/connection/channel/direct/AbstractDirectChannel.java
index b2b4e5d66..aab0794c6 100644
--- a/src/main/java/net/schmizz/sshj/connection/channel/direct/AbstractDirectChannel.java
+++ b/src/main/java/net/schmizz/sshj/connection/channel/direct/AbstractDirectChannel.java
@@ -16,7 +16,6 @@
 package net.schmizz.sshj.connection.channel.direct;
 
 import net.schmizz.sshj.common.Buffer;
-import net.schmizz.sshj.common.LoggerFactory;
 import net.schmizz.sshj.common.Message;
 import net.schmizz.sshj.common.SSHPacket;
 import net.schmizz.sshj.connection.Connection;
diff --git a/src/main/java/net/schmizz/sshj/transport/Transport.java b/src/main/java/net/schmizz/sshj/transport/Transport.java
index d6ed7116d..eb26caa42 100644
--- a/src/main/java/net/schmizz/sshj/transport/Transport.java
+++ b/src/main/java/net/schmizz/sshj/transport/Transport.java
@@ -18,7 +18,6 @@
 import net.schmizz.sshj.Config;
 import net.schmizz.sshj.Service;
 import net.schmizz.sshj.common.DisconnectReason;
-import net.schmizz.sshj.common.LoggerFactory;
 import net.schmizz.sshj.common.SSHPacket;
 import net.schmizz.sshj.common.SSHPacketHandler;
 import net.schmizz.sshj.transport.verification.AlgorithmsVerifier;

From cf5830eda56c5641e4e5ead97bbbc6e982abe39e Mon Sep 17 00:00:00 2001
From: David Solin <solind@Gallifrey.local>
Date: Wed, 24 Aug 2016 06:23:45 -0500
Subject: [PATCH 3/7] Indentation fixes.

---
 .../hierynomus/sshj/transport/IdentificationStringParser.java   | 2 +-
 src/main/java/net/schmizz/concurrent/Promise.java               | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/src/main/java/com/hierynomus/sshj/transport/IdentificationStringParser.java b/src/main/java/com/hierynomus/sshj/transport/IdentificationStringParser.java
index a4cbd6be2..87ede2bc7 100644
--- a/src/main/java/com/hierynomus/sshj/transport/IdentificationStringParser.java
+++ b/src/main/java/com/hierynomus/sshj/transport/IdentificationStringParser.java
@@ -31,7 +31,7 @@ public class IdentificationStringParser {
     private byte[] EXPECTED_START_BYTES = new byte[] {'S', 'S', 'H', '-'};
 
     public IdentificationStringParser(LoggerFactory loggerFactory, Buffer.PlainBuffer buffer) {
-	this.log = loggerFactory.getLogger(IdentificationStringParser.class);
+        this.log = loggerFactory.getLogger(IdentificationStringParser.class);
         this.buffer = buffer;
     }
 
diff --git a/src/main/java/net/schmizz/concurrent/Promise.java b/src/main/java/net/schmizz/concurrent/Promise.java
index f85080c5d..8e6cce3f6 100644
--- a/src/main/java/net/schmizz/concurrent/Promise.java
+++ b/src/main/java/net/schmizz/concurrent/Promise.java
@@ -64,7 +64,7 @@ public Promise(String name, ExceptionChainer<T> chainer, ReentrantLock lock, Log
         this.name = name;
         this.chainer = chainer;
         this.lock = lock == null ? new ReentrantLock() : lock;
-	this.log = loggerFactory.getLogger(getClass());
+        this.log = loggerFactory.getLogger(getClass());
         this.cond = this.lock.newCondition();
     }
 

From 6579f6f710de95761039f64f58bd6e4ad19fbe99 Mon Sep 17 00:00:00 2001
From: David Solin <solind@Gallifrey.local>
Date: Wed, 24 Aug 2016 07:34:01 -0500
Subject: [PATCH 4/7] Removed unnecessary DefaultLoggerFactory inner class from
 DefaultConfig Fixed license header in LoggerFactory.java (via gradle
 licenseForamat)

---
 .../java/net/schmizz/sshj/DefaultConfig.java   | 18 ------------------
 .../net/schmizz/sshj/common/LoggerFactory.java |  2 +-
 2 files changed, 1 insertion(+), 19 deletions(-)

diff --git a/src/main/java/net/schmizz/sshj/DefaultConfig.java b/src/main/java/net/schmizz/sshj/DefaultConfig.java
index c500d0231..06372a2ce 100644
--- a/src/main/java/net/schmizz/sshj/DefaultConfig.java
+++ b/src/main/java/net/schmizz/sshj/DefaultConfig.java
@@ -85,24 +85,6 @@ public DefaultConfig() {
         setKeepAliveProvider(KeepAliveProvider.HEARTBEAT);
     }
 
-    /**
-     * Default SLF4J-based implementation of the SSHJ LoggerFactory.
-     */
-    public static class DefaultLoggerFactory implements LoggerFactory {
-        private DefaultLoggerFactory() {
-        }
-
-        @Override
-        public Logger getLogger(String name) {
-            return org.slf4j.LoggerFactory.getLogger(name);
-        }
-
-        @Override
-        public Logger getLogger(Class<?> clazz) {
-            return org.slf4j.LoggerFactory.getLogger(clazz);
-        }
-    }
-
     @Override
     public void setLoggerFactory(LoggerFactory loggerFactory) {
 	super.setLoggerFactory(loggerFactory);
diff --git a/src/main/java/net/schmizz/sshj/common/LoggerFactory.java b/src/main/java/net/schmizz/sshj/common/LoggerFactory.java
index 536608404..1f1742c02 100644
--- a/src/main/java/net/schmizz/sshj/common/LoggerFactory.java
+++ b/src/main/java/net/schmizz/sshj/common/LoggerFactory.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C)2016 - SSHJ Contributors
+ * Copyright (C)2009 - SSHJ Contributors
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.

From 79c1ae2bb0df90d20a1b17a02407cb661e610e53 Mon Sep 17 00:00:00 2001
From: David Solin <solind@Gallifrey.local>
Date: Wed, 24 Aug 2016 08:08:33 -0500
Subject: [PATCH 5/7] Re-add public constructor used by Groovy

---
 .../hierynomus/sshj/transport/IdentificationStringParser.java | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/src/main/java/com/hierynomus/sshj/transport/IdentificationStringParser.java b/src/main/java/com/hierynomus/sshj/transport/IdentificationStringParser.java
index 87ede2bc7..ef9f9cf5f 100644
--- a/src/main/java/com/hierynomus/sshj/transport/IdentificationStringParser.java
+++ b/src/main/java/com/hierynomus/sshj/transport/IdentificationStringParser.java
@@ -30,6 +30,10 @@ public class IdentificationStringParser {
 
     private byte[] EXPECTED_START_BYTES = new byte[] {'S', 'S', 'H', '-'};
 
+    public IdentificationStringParser(Buffer.PlainBuffer buffer) {
+	this(LoggerFactory.DEFAULT, buffer);
+    }
+
     public IdentificationStringParser(LoggerFactory loggerFactory, Buffer.PlainBuffer buffer) {
         this.log = loggerFactory.getLogger(IdentificationStringParser.class);
         this.buffer = buffer;

From 3f29879ecaac6e4141e448a8d64173d0825f3c27 Mon Sep 17 00:00:00 2001
From: David Solin <solind@Gallifrey.local>
Date: Wed, 24 Aug 2016 08:35:08 -0500
Subject: [PATCH 6/7] Test fixes

---
 src/test/java/net/schmizz/sshj/sftp/PacketReaderTest.java | 2 ++
 src/test/java/net/schmizz/sshj/sftp/SFTPClientTest.java   | 5 ++++-
 2 files changed, 6 insertions(+), 1 deletion(-)

diff --git a/src/test/java/net/schmizz/sshj/sftp/PacketReaderTest.java b/src/test/java/net/schmizz/sshj/sftp/PacketReaderTest.java
index 37507f1d5..234a520e0 100644
--- a/src/test/java/net/schmizz/sshj/sftp/PacketReaderTest.java
+++ b/src/test/java/net/schmizz/sshj/sftp/PacketReaderTest.java
@@ -15,6 +15,7 @@
  */
 package net.schmizz.sshj.sftp;
 
+import net.schmizz.sshj.common.LoggerFactory;
 import net.schmizz.sshj.common.SSHException;
 import net.schmizz.sshj.connection.channel.direct.Session.Subsystem;
 import org.junit.Before;
@@ -43,6 +44,7 @@ public void setUp() throws Exception {
 
         engine = Mockito.mock(SFTPEngine.class);
         subsystem = Mockito.mock(Subsystem.class);
+        Mockito.when(engine.getLoggerFactory()).thenReturn(LoggerFactory.DEFAULT);
         Mockito.when(engine.getSubsystem()).thenReturn(subsystem);
         Mockito.when(subsystem.getInputStream()).thenReturn(pipedin);
 
diff --git a/src/test/java/net/schmizz/sshj/sftp/SFTPClientTest.java b/src/test/java/net/schmizz/sshj/sftp/SFTPClientTest.java
index 349f0eec6..eb6dfaaee 100644
--- a/src/test/java/net/schmizz/sshj/sftp/SFTPClientTest.java
+++ b/src/test/java/net/schmizz/sshj/sftp/SFTPClientTest.java
@@ -20,12 +20,13 @@
 
 import java.io.IOException;
 
+import net.schmizz.sshj.common.LoggerFactory;
+
 import static net.schmizz.sshj.sftp.PathHelper.DEFAULT_PATH_SEPARATOR;
 import static org.mockito.Mockito.*;
 
 public class SFTPClientTest {
     private final SFTPEngine sftpEngine = mock(SFTPEngine.class);
-    private final SFTPClient client = new SFTPClient(sftpEngine);
 
     @Before
     public void setPathHelper() throws Exception {
@@ -39,6 +40,7 @@ public String canonicalize(String path)
             }
         }, DEFAULT_PATH_SEPARATOR);
         when(sftpEngine.getPathHelper()).thenReturn(helper);
+        when(sftpEngine.getLoggerFactory()).thenReturn(LoggerFactory.DEFAULT);
     }
 
     @Before
@@ -49,6 +51,7 @@ public void setRemoteWorkingDirectory() throws IOException {
 
     @Test
     public void doesNotTryToCreateDirectoryTwiceWhenPathHasTrailingSeparator() throws Exception {
+        SFTPClient client = new SFTPClient(sftpEngine);
         client.mkdirs("/folder/directory/");
         verify(sftpEngine, times(1)).makeDir("/folder/directory");
     }

From 9425300262a83ce5cb75258f8bcf261a6b4c37e0 Mon Sep 17 00:00:00 2001
From: David Solin <solind@Gallifrey.local>
Date: Mon, 29 Aug 2016 15:19:06 -0500
Subject: [PATCH 7/7] Better argument order for IdentificationStringParser
 constructor.

---
 .../hierynomus/sshj/transport/IdentificationStringParser.java | 4 ++--
 src/main/java/net/schmizz/sshj/transport/TransportImpl.java   | 2 +-
 2 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/src/main/java/com/hierynomus/sshj/transport/IdentificationStringParser.java b/src/main/java/com/hierynomus/sshj/transport/IdentificationStringParser.java
index ef9f9cf5f..7c23475ec 100644
--- a/src/main/java/com/hierynomus/sshj/transport/IdentificationStringParser.java
+++ b/src/main/java/com/hierynomus/sshj/transport/IdentificationStringParser.java
@@ -31,10 +31,10 @@ public class IdentificationStringParser {
     private byte[] EXPECTED_START_BYTES = new byte[] {'S', 'S', 'H', '-'};
 
     public IdentificationStringParser(Buffer.PlainBuffer buffer) {
-	this(LoggerFactory.DEFAULT, buffer);
+	this(buffer, LoggerFactory.DEFAULT);
     }
 
-    public IdentificationStringParser(LoggerFactory loggerFactory, Buffer.PlainBuffer buffer) {
+    public IdentificationStringParser(Buffer.PlainBuffer buffer, LoggerFactory loggerFactory) {
         this.log = loggerFactory.getLogger(IdentificationStringParser.class);
         this.buffer = buffer;
     }
diff --git a/src/main/java/net/schmizz/sshj/transport/TransportImpl.java b/src/main/java/net/schmizz/sshj/transport/TransportImpl.java
index 561b6ea63..0ea1ea845 100644
--- a/src/main/java/net/schmizz/sshj/transport/TransportImpl.java
+++ b/src/main/java/net/schmizz/sshj/transport/TransportImpl.java
@@ -219,7 +219,7 @@ private void sendClientIdent() throws IOException {
      */
     private String readIdentification(Buffer.PlainBuffer buffer)
             throws IOException {
-        String ident = new IdentificationStringParser(loggerFactory, buffer).parseIdentificationString();
+        String ident = new IdentificationStringParser(buffer, loggerFactory).parseIdentificationString();
         if (ident.isEmpty()) {
             return ident;
         }