GH-275: More logging for SFTP clients
Log all SFTP requests and replies at debug level, and include the
command name in the log message. A simple grep for SSH_FXP or SSH_FX
should then find all lines relating to SFTP commands.
diff --git a/sshd-sftp/src/main/java/org/apache/sshd/sftp/client/impl/AbstractSftpClient.java b/sshd-sftp/src/main/java/org/apache/sshd/sftp/client/impl/AbstractSftpClient.java
index dcaab29..cdea1ec 100644
--- a/sshd-sftp/src/main/java/org/apache/sshd/sftp/client/impl/AbstractSftpClient.java
+++ b/sshd-sftp/src/main/java/org/apache/sshd/sftp/client/impl/AbstractSftpClient.java
@@ -197,18 +197,20 @@
* @see #throwStatusException(int, int, SftpStatus)
*/
protected void checkResponseStatus(int cmd, int id, SftpStatus status) throws IOException {
- if (log.isTraceEnabled()) {
- log.trace("checkResponseStatus({})[id={}] cmd={} status={}",
- getClientChannel(), id, SftpConstants.getCommandMessageName(cmd),
- status);
- }
-
if (!status.isOk()) {
throwStatusException(cmd, id, status);
+ } else if (log.isTraceEnabled()) {
+ log.trace("throwStatusException({})[id={}] cmd={} status={}",
+ getClientChannel(), id, SftpConstants.getCommandMessageName(cmd),
+ status);
}
}
protected void throwStatusException(int cmd, int id, SftpStatus status) throws IOException {
+ if (log.isDebugEnabled()) {
+ log.debug("throwStatusException({})[id={}] cmd={} status={}", getClientChannel(), id,
+ SftpConstants.getCommandMessageName(cmd), status);
+ }
throw new SftpException(status.getStatusCode(), status.getMessage());
}
@@ -239,12 +241,7 @@
}
if (type == SftpConstants.SSH_FXP_STATUS) {
- SftpStatus status = SftpStatus.parse(buffer);
- if (log.isTraceEnabled()) {
- log.trace("checkHandleResponse({})[id={}] {} - status: {}", getClientChannel(), id,
- SftpConstants.getCommandMessageName(cmd), status);
- }
- throwStatusException(cmd, id, status);
+ throwStatusException(cmd, id, SftpStatus.parse(buffer));
}
return handleUnexpectedHandlePacket(cmd, id, type, length, buffer);
@@ -286,12 +283,7 @@
}
if (type == SftpConstants.SSH_FXP_STATUS) {
- SftpStatus status = SftpStatus.parse(buffer);
- if (log.isTraceEnabled()) {
- log.trace("checkAttributesResponse({})[id={}] {} - status: {}", getClientChannel(), id,
- SftpConstants.getCommandMessageName(cmd), status);
- }
- throwStatusException(cmd, id, status);
+ throwStatusException(cmd, id, SftpStatus.parse(buffer));
}
return handleUnexpectedAttributesPacket(cmd, id, type, length, buffer);
@@ -355,13 +347,7 @@
}
if (type == SftpConstants.SSH_FXP_STATUS) {
- SftpStatus status = SftpStatus.parse(buffer);
- if (log.isTraceEnabled()) {
- log.trace("checkOneNameResponse({})[id={}] {} status: {}", getClientChannel(), id,
- SftpConstants.getCommandMessageName(cmd), status);
- }
-
- throwStatusException(cmd, id, status);
+ throwStatusException(cmd, id, SftpStatus.parse(buffer));
}
return handleUnknownOneNamePacket(cmd, id, type, length, buffer);
@@ -556,6 +542,9 @@
buffer.putInt(mode);
buffer = writeAttributes(SftpConstants.SSH_FXP_OPEN, buffer, fileOpenAttributes);
+ if (log.isDebugEnabled()) {
+ log.debug("open({}): send SSH_FXP_OPEN {}", getClientChannel(), path);
+ }
CloseableHandle handle = new DefaultCloseableHandle(this, path, checkHandle(SftpConstants.SSH_FXP_OPEN, buffer));
if (log.isTraceEnabled()) {
log.trace("open({})[{}] options={}: {}", getClientChannel(), path, options, handle);
@@ -576,6 +565,9 @@
byte[] id = Objects.requireNonNull(handle, "No handle").getIdentifier();
Buffer buffer = new ByteArrayBuffer(id.length + Long.SIZE /* some extra fields */, false);
buffer.putBytes(id);
+ if (log.isDebugEnabled()) {
+ log.debug("open({})[{}]: send SSH_FXP_CLOSE", getClientChannel(), handle);
+ }
checkCommandStatus(SftpConstants.SSH_FXP_CLOSE, buffer);
}
@@ -683,13 +675,12 @@
if (type == SftpConstants.SSH_FXP_STATUS) {
SftpStatus status = SftpStatus.parse(buffer);
- if (log.isTraceEnabled()) {
- log.trace("checkDataResponse({})[id={}] {} status: {}",
- getClientChannel(), id, SftpConstants.getCommandMessageName(cmd),
- status);
- }
if (status.getStatusCode() == SftpConstants.SSH_FX_EOF) {
+ if (log.isTraceEnabled()) {
+ log.trace("checkDataResponse({})[id={}] {} status: {}", getClientChannel(), id,
+ SftpConstants.getCommandMessageName(cmd), status);
+ }
return -1;
}
@@ -771,7 +762,7 @@
}
if (log.isDebugEnabled()) {
- log.debug("mkdir({}) {}", getClientChannel(), path);
+ log.debug("mkdir({}): send SSH_FXP_MKDIR {}", getClientChannel(), path);
}
Buffer buffer = new ByteArrayBuffer(path.length() + Long.SIZE /* some extra fields */, false);
@@ -793,7 +784,7 @@
}
if (log.isDebugEnabled()) {
- log.debug("rmdir({}) {}", getClientChannel(), path);
+ log.debug("rmdir({}): send SSH_FXP_RMDIR {}", getClientChannel(), path);
}
Buffer buffer = new ByteArrayBuffer(path.length() + Long.SIZE /* some extra fields */, false);
@@ -810,6 +801,9 @@
Buffer buffer = new ByteArrayBuffer(path.length() + Long.SIZE /* some extra fields */, false);
buffer = putReferencedName(SftpConstants.SSH_FXP_OPENDIR, buffer, path, 0);
+ if (log.isDebugEnabled()) {
+ log.debug("openDir({}): send SSH_FXP_OPENDIR {}", getClientChannel(), path);
+ }
CloseableHandle handle = new DefaultCloseableHandle(this, path, checkHandle(SftpConstants.SSH_FXP_OPENDIR, buffer));
if (log.isTraceEnabled()) {
log.trace("openDir({})[{}]: {}", getClientChannel(), path, handle);
@@ -831,6 +825,9 @@
Buffer buffer = new ByteArrayBuffer(id.length + Byte.SIZE /* some extra fields */, false);
buffer.putBytes(id);
+ if (log.isDebugEnabled()) {
+ log.debug("readDir({})[{}]: send SSH_FXP_READDIR", getClientChannel(), handle);
+ }
int cmdId = send(SftpConstants.SSH_FXP_READDIR, buffer);
Buffer response = receive(cmdId);
return checkDirResponse(SftpConstants.SSH_FXP_READDIR, response, eolIndicator);
@@ -895,11 +892,11 @@
if (type == SftpConstants.SSH_FXP_STATUS) {
SftpStatus status = SftpStatus.parse(buffer);
- if (traceEnabled) {
- log.trace("checkDirResponse({})[id={}] - status: {}", getClientChannel(), id, status);
- }
if (status.getStatusCode() == SftpConstants.SSH_FX_EOF) {
+ if (traceEnabled) {
+ log.trace("checkDirResponse({})[id={}] - status: {}", getClientChannel(), id, status);
+ }
return null;
}
@@ -918,6 +915,29 @@
+ " in response to " + SftpConstants.getCommandMessageName(cmd)
+ ": type=" + SftpConstants.getCommandMessageName(type) + ", id=" + id);
}
+ if (log.isDebugEnabled()) {
+ if (type == SftpConstants.SSH_FXP_STATUS && remaining >= 4) {
+ int rpos = buffer.rpos();
+ int status = buffer.getInt();
+ buffer.rpos(rpos);
+ if (status == SftpConstants.SSH_FX_OK
+ && (cmd == SftpConstants.SSH_FXP_WRITE || cmd == SftpConstants.SSH_FXP_READ)) {
+ // Only trace logging for data read/write if the status is OK
+ if (log.isTraceEnabled()) {
+ log.trace("validateIncomingResponse({}): received {}({}) for command {} (id={})", getClientChannel(),
+ SftpConstants.getCommandMessageName(type), SftpConstants.getStatusName(status),
+ SftpConstants.getCommandMessageName(cmd), id);
+ }
+ } else {
+ log.debug("validateIncomingResponse({}): received {}({}) for command {} (id={})", getClientChannel(),
+ SftpConstants.getCommandMessageName(type), SftpConstants.getStatusName(status),
+ SftpConstants.getCommandMessageName(cmd), id);
+ }
+ } else {
+ log.debug("validateIncomingResponse({}): received {} for command {} (id={})", getClientChannel(),
+ SftpConstants.getCommandMessageName(type), SftpConstants.getCommandMessageName(cmd), id);
+ }
+ }
}
protected List<DirEntry> handleUnknownDirListingPacket(
@@ -958,6 +978,9 @@
Buffer buffer = new ByteArrayBuffer(path.length() + Long.SIZE, false);
buffer = putReferencedName(SftpConstants.SSH_FXP_REALPATH, buffer, path, 0);
+ if (log.isDebugEnabled()) {
+ log.debug("canonicalPath({}): send SSH_FXP_REALPATH {}", getClientChannel(), path);
+ }
return checkOneName(SftpConstants.SSH_FXP_REALPATH, buffer);
}
@@ -975,6 +998,9 @@
buffer.putInt(SftpConstants.SSH_FILEXFER_ATTR_ALL);
}
+ if (log.isDebugEnabled()) {
+ log.debug("stat({}): send SSH_FXP_STAT {}", getClientChannel(), path);
+ }
return checkAttributes(SftpConstants.SSH_FXP_STAT, buffer);
}
@@ -992,6 +1018,9 @@
buffer.putInt(SftpConstants.SSH_FILEXFER_ATTR_ALL);
}
+ if (log.isDebugEnabled()) {
+ log.debug("stat({}): send SSH_FXP_LSTAT {}", getClientChannel(), path);
+ }
return checkAttributes(SftpConstants.SSH_FXP_LSTAT, buffer);
}
@@ -1010,6 +1039,9 @@
buffer.putInt(SftpConstants.SSH_FILEXFER_ATTR_ALL);
}
+ if (log.isDebugEnabled()) {
+ log.debug("stat({}): send SSH_FXP_FSTAT {}", getClientChannel(), handle);
+ }
return checkAttributes(SftpConstants.SSH_FXP_FSTAT, buffer);
}
@@ -1026,6 +1058,9 @@
Buffer buffer = new ByteArrayBuffer();
buffer = putReferencedName(SftpConstants.SSH_FXP_SETSTAT, buffer, path, 0);
buffer = writeAttributes(SftpConstants.SSH_FXP_SETSTAT, buffer, attributes);
+ if (log.isDebugEnabled()) {
+ log.debug("setStat({}): send SSH_FXP_SETSTAT {}", getClientChannel(), path);
+ }
checkCommandStatus(SftpConstants.SSH_FXP_SETSTAT, buffer);
}
@@ -1042,6 +1077,9 @@
Buffer buffer = new ByteArrayBuffer(id.length + (2 * Long.SIZE) /* some extras */, false);
buffer.putBytes(id);
buffer = writeAttributes(SftpConstants.SSH_FXP_FSETSTAT, buffer, attributes);
+ if (log.isDebugEnabled()) {
+ log.debug("setStat({}): send SSH_FXP_FSETSTAT {}", getClientChannel(), handle);
+ }
checkCommandStatus(SftpConstants.SSH_FXP_FSETSTAT, buffer);
}
@@ -1053,6 +1091,9 @@
Buffer buffer = new ByteArrayBuffer(path.length() + Long.SIZE /* some extra fields */, false);
buffer = putReferencedName(SftpConstants.SSH_FXP_READLINK, buffer, path, 0);
+ if (log.isDebugEnabled()) {
+ log.debug("readLink({}): send SSH_FXP_READLINK {}", getClientChannel(), path);
+ }
return checkOneName(SftpConstants.SSH_FXP_READLINK, buffer);
}
@@ -1062,27 +1103,26 @@
throw new IOException("link(" + linkPath + " => " + targetPath + ")[symbolic=" + symbolic + "] client is closed");
}
+ int version = getVersion();
+ int cmd = version < SftpConstants.SFTP_V6 ? SftpConstants.SSH_FXP_SYMLINK : SftpConstants.SSH_FXP_LINK;
if (log.isDebugEnabled()) {
- log.debug("link({})[symbolic={}] {} => {}", getClientChannel(), symbolic, linkPath, targetPath);
+ log.debug("link({})[symbolic={}] send {} {} => {}", getClientChannel(), symbolic,
+ SshConstants.getCommandMessageName(cmd), linkPath, targetPath);
}
Buffer buffer = new ByteArrayBuffer(linkPath.length() + targetPath.length() + Long.SIZE /* some extra fields */, false);
- int version = getVersion();
if (version < SftpConstants.SFTP_V6) {
if (!symbolic) {
throw new UnsupportedOperationException("Hard links are not supported in sftp v" + version);
}
- buffer = putReferencedName(SftpConstants.SSH_FXP_SYMLINK, buffer, targetPath, 0);
- buffer = putReferencedName(SftpConstants.SSH_FXP_SYMLINK, buffer, linkPath, 1);
-
- checkCommandStatus(SftpConstants.SSH_FXP_SYMLINK, buffer);
+ buffer = putReferencedName(cmd, buffer, targetPath, 0);
+ buffer = putReferencedName(cmd, buffer, linkPath, 1);
} else {
- buffer = putReferencedName(SftpConstants.SSH_FXP_SYMLINK, buffer, targetPath, 0);
- buffer = putReferencedName(SftpConstants.SSH_FXP_SYMLINK, buffer, linkPath, 1);
+ buffer = putReferencedName(cmd, buffer, targetPath, 0);
+ buffer = putReferencedName(cmd, buffer, linkPath, 1);
buffer.putBoolean(symbolic);
-
- checkCommandStatus(SftpConstants.SSH_FXP_LINK, buffer);
}
+ checkCommandStatus(cmd, buffer);
}
@Override
@@ -1093,17 +1133,16 @@
+ "] client is closed");
}
- if (log.isDebugEnabled()) {
- log.debug("lock({})[{}] offset={}, length={}, mask=0x{}",
- getClientChannel(), handle, offset, length, Integer.toHexString(mask));
- }
-
byte[] id = Objects.requireNonNull(handle, "No handle").getIdentifier();
Buffer buffer = new ByteArrayBuffer(id.length + Long.SIZE /* a bit extra */, false);
buffer.putBytes(id);
buffer.putLong(offset);
buffer.putLong(length);
buffer.putInt(mask);
+ if (log.isDebugEnabled()) {
+ log.debug("lock({})[{}] send SSH_FXP_BLOCK offset={}, length={}, mask=0x{}", getClientChannel(), handle, offset,
+ length, Integer.toHexString(mask));
+ }
checkCommandStatus(SftpConstants.SSH_FXP_BLOCK, buffer);
}
@@ -1113,15 +1152,14 @@
throw new IOException("unlock" + handle + ")[offset=" + offset + ", length=" + length + "] client is closed");
}
- if (log.isDebugEnabled()) {
- log.debug("unlock({})[{}] offset={}, length={}", getClientChannel(), handle, offset, length);
- }
-
byte[] id = Objects.requireNonNull(handle, "No handle").getIdentifier();
Buffer buffer = new ByteArrayBuffer(id.length + Long.SIZE /* a bit extra */, false);
buffer.putBytes(id);
buffer.putLong(offset);
buffer.putLong(length);
+ if (log.isDebugEnabled()) {
+ log.debug("unlock({})[{}] send SSH_FXP_UNBLOCK offset={}, length={}", getClientChannel(), handle, offset, length);
+ }
checkCommandStatus(SftpConstants.SSH_FXP_UNBLOCK, buffer);
}
diff --git a/sshd-sftp/src/main/java/org/apache/sshd/sftp/client/impl/DefaultSftpClient.java b/sshd-sftp/src/main/java/org/apache/sshd/sftp/client/impl/DefaultSftpClient.java
index 5d290d9..aec1ca8 100644
--- a/sshd-sftp/src/main/java/org/apache/sshd/sftp/client/impl/DefaultSftpClient.java
+++ b/sshd-sftp/src/main/java/org/apache/sshd/sftp/client/impl/DefaultSftpClient.java
@@ -416,12 +416,7 @@
extensions.put(name, data);
}
} else if (type == SftpConstants.SSH_FXP_STATUS) {
- SftpStatus status = SftpStatus.parse(buffer);
- if (traceEnabled) {
- log.trace("handleInitResponse({})[id={}] - status: {}", clientChannel, id, status);
- }
-
- throwStatusException(SftpConstants.SSH_FXP_INIT, id, status);
+ throwStatusException(SftpConstants.SSH_FXP_INIT, id, SftpStatus.parse(buffer));
} else {
IOException err = handleUnexpectedPacket(
SftpConstants.SSH_FXP_INIT, SftpConstants.SSH_FXP_VERSION, id, type, length, buffer);