mirror of https://github.com/apache/jclouds.git
Merge pull request #110 from jsonking/720-jsch-driver-logging
Issue 720: Log the ssh key fingerprint information for jsch
This commit is contained in:
commit
e9029db0ba
|
@ -44,6 +44,14 @@
|
||||||
</repository>
|
</repository>
|
||||||
</repositories>
|
</repositories>
|
||||||
|
|
||||||
|
<properties>
|
||||||
|
<test.ssh.host>localhost</test.ssh.host>
|
||||||
|
<test.ssh.port>22</test.ssh.port>
|
||||||
|
<test.ssh.username />
|
||||||
|
<test.ssh.password />
|
||||||
|
<test.ssh.keyfile />
|
||||||
|
</properties>
|
||||||
|
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.jclouds</groupId>
|
<groupId>org.jclouds</groupId>
|
||||||
|
@ -62,6 +70,17 @@
|
||||||
<type>test-jar</type>
|
<type>test-jar</type>
|
||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.jclouds.driver</groupId>
|
||||||
|
<artifactId>jclouds-slf4j</artifactId>
|
||||||
|
<version>${project.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>ch.qos.logback</groupId>
|
||||||
|
<artifactId>logback-classic</artifactId>
|
||||||
|
<version>0.9.30</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.jcraft</groupId>
|
<groupId>com.jcraft</groupId>
|
||||||
<artifactId>jsch</artifactId>
|
<artifactId>jsch</artifactId>
|
||||||
|
@ -89,4 +108,66 @@
|
||||||
</plugin>
|
</plugin>
|
||||||
</plugins>
|
</plugins>
|
||||||
</build>
|
</build>
|
||||||
|
<profiles>
|
||||||
|
<profile>
|
||||||
|
<id>live</id>
|
||||||
|
<build>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-surefire-plugin</artifactId>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<id>integration</id>
|
||||||
|
<phase>integration-test</phase>
|
||||||
|
<goals>
|
||||||
|
<goal>test</goal>
|
||||||
|
</goals>
|
||||||
|
<configuration>
|
||||||
|
<!-- note that the groups/excluded groups don't work due to some problem
|
||||||
|
in surefire or testng. instead, we have to exclude via file path
|
||||||
|
<groups>live,integration</groups>
|
||||||
|
<excludedGroups>unit,performance</excludedGroups>
|
||||||
|
-->
|
||||||
|
<excludes>
|
||||||
|
<exclude>none</exclude>
|
||||||
|
</excludes>
|
||||||
|
<includes>
|
||||||
|
<include>**/*IntegrationTest.java</include>
|
||||||
|
<include>**/*LiveTest.java</include>
|
||||||
|
</includes>
|
||||||
|
<systemProperties>
|
||||||
|
<property>
|
||||||
|
<name>file.encoding</name>
|
||||||
|
<value>UTF-8</value>
|
||||||
|
</property>
|
||||||
|
<property>
|
||||||
|
<name>test.ssh.host</name>
|
||||||
|
<value>${test.ssh.host}</value>
|
||||||
|
</property>
|
||||||
|
<property>
|
||||||
|
<name>test.ssh.port</name>
|
||||||
|
<value>${test.ssh.port}</value>
|
||||||
|
</property>
|
||||||
|
<property>
|
||||||
|
<name>test.ssh.username</name>
|
||||||
|
<value>${test.ssh.username}</value>
|
||||||
|
</property>
|
||||||
|
<property>
|
||||||
|
<name>test.ssh.keyfile</name>
|
||||||
|
<value>${test.ssh.keyfile}</value>
|
||||||
|
</property>
|
||||||
|
<property>
|
||||||
|
<name>test.ssh.password</name>
|
||||||
|
<value>${test.ssh.password}</value>
|
||||||
|
</property>
|
||||||
|
</systemProperties>
|
||||||
|
</configuration>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
</profile>
|
||||||
|
</profiles>
|
||||||
</project>
|
</project>
|
||||||
|
|
|
@ -25,6 +25,8 @@ import static com.google.common.base.Predicates.instanceOf;
|
||||||
import static com.google.common.base.Predicates.or;
|
import static com.google.common.base.Predicates.or;
|
||||||
import static com.google.common.base.Throwables.getCausalChain;
|
import static com.google.common.base.Throwables.getCausalChain;
|
||||||
import static com.google.common.collect.Iterables.any;
|
import static com.google.common.collect.Iterables.any;
|
||||||
|
import static org.jclouds.crypto.SshKeys.fingerprintPrivateKey;
|
||||||
|
import static org.jclouds.crypto.SshKeys.sha1PrivateKey;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
|
@ -90,6 +92,7 @@ public class JschSshClient implements SshClient {
|
||||||
private final int port;
|
private final int port;
|
||||||
private final String username;
|
private final String username;
|
||||||
private final String password;
|
private final String password;
|
||||||
|
private final String toString;
|
||||||
|
|
||||||
@Inject(optional = true)
|
@Inject(optional = true)
|
||||||
@Named("jclouds.ssh.max-retries")
|
@Named("jclouds.ssh.max-retries")
|
||||||
|
@ -131,6 +134,14 @@ public class JschSshClient implements SshClient {
|
||||||
this.timeout = timeout;
|
this.timeout = timeout;
|
||||||
this.password = password;
|
this.password = password;
|
||||||
this.privateKey = privateKey;
|
this.privateKey = privateKey;
|
||||||
|
if ( privateKey==null ) {
|
||||||
|
this.toString = String.format("%s:password@%s:%d", username, host, port);
|
||||||
|
} else {
|
||||||
|
String fingerPrint = fingerprintPrivateKey(new String(privateKey));
|
||||||
|
String sha1 = sha1PrivateKey(new String(privateKey));
|
||||||
|
this.toString = String.format("%s:rsa[fingerprint(%s),sha1(%s)]@%s:%d", username, fingerPrint, sha1, host,
|
||||||
|
port);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -182,7 +193,7 @@ public class JschSshClient implements SshClient {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return String.format("Session(%s)", JschSshClient.this.toString());
|
return String.format("Session(timeout=%d)", timeout);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -237,7 +248,7 @@ public class JschSshClient implements SshClient {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "ChannelSftp(" + JschSshClient.this.toString() + ")";
|
return "ChannelSftp()";
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -263,7 +274,7 @@ public class JschSshClient implements SshClient {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "Payload(" + JschSshClient.this.toString() + ")[" + path + "]";
|
return "Payload(path=[" + path + "])";
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -301,7 +312,7 @@ public class JschSshClient implements SshClient {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "Put(" + JschSshClient.this.toString() + ")[" + path + "]";
|
return "Put(path=[" + path + "])";
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -354,7 +365,7 @@ public class JschSshClient implements SshClient {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return String.format("%s@%s:%d", username, host, port);
|
return toString;
|
||||||
}
|
}
|
||||||
|
|
||||||
@PreDestroy
|
@PreDestroy
|
||||||
|
@ -389,7 +400,7 @@ public class JschSshClient implements SshClient {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "ChannelExec(" + JschSshClient.this.toString() + ")";
|
return "ChannelExec()";
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -437,7 +448,7 @@ public class JschSshClient implements SshClient {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "ExecResponse(" + JschSshClient.this.toString() + ")[" + command + "]";
|
return "ExecResponse(command=[" + command + "])";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -24,11 +24,13 @@ import java.io.File;
|
||||||
import java.io.FileInputStream;
|
import java.io.FileInputStream;
|
||||||
import java.io.FileNotFoundException;
|
import java.io.FileNotFoundException;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.net.InetAddress;
|
||||||
|
|
||||||
import org.jclouds.compute.domain.ExecResponse;
|
import org.jclouds.compute.domain.ExecResponse;
|
||||||
import org.jclouds.domain.Credentials;
|
import org.jclouds.domain.Credentials;
|
||||||
import org.jclouds.io.Payload;
|
import org.jclouds.io.Payload;
|
||||||
import org.jclouds.io.Payloads;
|
import org.jclouds.io.Payloads;
|
||||||
|
import org.jclouds.logging.slf4j.config.SLF4JLoggingModule;
|
||||||
import org.jclouds.net.IPSocket;
|
import org.jclouds.net.IPSocket;
|
||||||
import org.jclouds.ssh.SshClient;
|
import org.jclouds.ssh.SshClient;
|
||||||
import org.jclouds.ssh.jsch.config.JschSshClientModule;
|
import org.jclouds.ssh.jsch.config.JschSshClientModule;
|
||||||
|
@ -44,7 +46,7 @@ import com.google.inject.Injector;
|
||||||
*
|
*
|
||||||
* @author Adrian Cole
|
* @author Adrian Cole
|
||||||
*/
|
*/
|
||||||
@Test(groups = "live")
|
@Test(groups = "live", testName = "JschSshClientLiveTest" )
|
||||||
public class JschSshClientLiveTest {
|
public class JschSshClientLiveTest {
|
||||||
protected static final String sshHost = System.getProperty("test.ssh.host", "localhost");
|
protected static final String sshHost = System.getProperty("test.ssh.host", "localhost");
|
||||||
protected static final String sshPort = System.getProperty("test.ssh.port", "22");
|
protected static final String sshPort = System.getProperty("test.ssh.port", "22");
|
||||||
|
@ -106,7 +108,7 @@ public class JschSshClientLiveTest {
|
||||||
|
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
Injector i = Guice.createInjector(new JschSshClientModule());
|
Injector i = Guice.createInjector(new JschSshClientModule(), new SLF4JLoggingModule());
|
||||||
SshClient.Factory factory = i.getInstance(SshClient.Factory.class);
|
SshClient.Factory factory = i.getInstance(SshClient.Factory.class);
|
||||||
SshClient connection;
|
SshClient connection;
|
||||||
if (sshKeyFile != null && !sshKeyFile.trim().equals("")) {
|
if (sshKeyFile != null && !sshKeyFile.trim().equals("")) {
|
||||||
|
@ -139,7 +141,8 @@ public class JschSshClientLiveTest {
|
||||||
public void testExecHostname() throws IOException {
|
public void testExecHostname() throws IOException {
|
||||||
ExecResponse response = setupClient().exec("hostname");
|
ExecResponse response = setupClient().exec("hostname");
|
||||||
assertEquals(response.getError(), "");
|
assertEquals(response.getError(), "");
|
||||||
assertEquals(response.getOutput().trim(), sshHost);
|
assertEquals(response.getOutput().trim(), "localhost".equals(sshHost) ? InetAddress.getLocalHost().getHostName()
|
||||||
|
: sshHost);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -21,8 +21,11 @@ package org.jclouds.ssh.jsch;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.net.ConnectException;
|
import java.net.ConnectException;
|
||||||
import java.net.UnknownHostException;
|
import java.net.UnknownHostException;
|
||||||
|
import java.util.Properties;
|
||||||
|
|
||||||
|
import com.google.inject.AbstractModule;
|
||||||
import org.jclouds.domain.Credentials;
|
import org.jclouds.domain.Credentials;
|
||||||
|
import org.jclouds.logging.slf4j.config.SLF4JLoggingModule;
|
||||||
import org.jclouds.net.IPSocket;
|
import org.jclouds.net.IPSocket;
|
||||||
import org.jclouds.rest.AuthorizationException;
|
import org.jclouds.rest.AuthorizationException;
|
||||||
import org.jclouds.ssh.SshClient;
|
import org.jclouds.ssh.SshClient;
|
||||||
|
@ -38,6 +41,8 @@ import com.jcraft.jsch.ChannelSftp;
|
||||||
import com.jcraft.jsch.JSchException;
|
import com.jcraft.jsch.JSchException;
|
||||||
import com.jcraft.jsch.SftpException;
|
import com.jcraft.jsch.SftpException;
|
||||||
|
|
||||||
|
import static com.google.inject.name.Names.bindProperties;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @author Adrian Cole
|
* @author Adrian Cole
|
||||||
|
@ -49,11 +54,20 @@ public class JschSshClientTest {
|
||||||
|
|
||||||
@BeforeTest
|
@BeforeTest
|
||||||
public void setupSsh() throws UnknownHostException {
|
public void setupSsh() throws UnknownHostException {
|
||||||
ssh = createClient();
|
ssh = createClient(new Properties());
|
||||||
}
|
}
|
||||||
|
|
||||||
protected JschSshClient createClient() throws UnknownHostException {
|
protected JschSshClient createClient() throws UnknownHostException {
|
||||||
Injector i = Guice.createInjector(module());
|
return createClient(new Properties());
|
||||||
|
}
|
||||||
|
|
||||||
|
protected JschSshClient createClient(final Properties props) throws UnknownHostException {
|
||||||
|
Injector i = Guice.createInjector(module(), new AbstractModule() {
|
||||||
|
@Override
|
||||||
|
protected void configure() {
|
||||||
|
bindProperties(binder(), props);
|
||||||
|
}
|
||||||
|
}, new SLF4JLoggingModule());
|
||||||
SshClient.Factory factory = i.getInstance(SshClient.Factory.class);
|
SshClient.Factory factory = i.getInstance(SshClient.Factory.class);
|
||||||
JschSshClient ssh = JschSshClient.class.cast(factory.create(new IPSocket("localhost", 22), new Credentials(
|
JschSshClient ssh = JschSshClient.class.cast(factory.create(new IPSocket("localhost", 22), new Credentials(
|
||||||
"username", "password")));
|
"username", "password")));
|
||||||
|
@ -83,6 +97,13 @@ public class JschSshClientTest {
|
||||||
assert ssh1.shouldRetry(new AuthorizationException("problem", null));
|
assert ssh1.shouldRetry(new AuthorizationException("problem", null));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void testOnlyRetryAuthWhenSetViaProperties() throws UnknownHostException {
|
||||||
|
Properties props = new Properties();
|
||||||
|
props.setProperty("jclouds.ssh.retry-auth", "true");
|
||||||
|
JschSshClient ssh1 = createClient(props);
|
||||||
|
assert ssh1.shouldRetry(new AuthorizationException("problem", null));
|
||||||
|
}
|
||||||
|
|
||||||
public void testExceptionMessagesRetry() {
|
public void testExceptionMessagesRetry() {
|
||||||
assert !ssh.shouldRetry(new NullPointerException(""));
|
assert !ssh.shouldRetry(new NullPointerException(""));
|
||||||
assert !ssh.shouldRetry(new NullPointerException((String) null));
|
assert !ssh.shouldRetry(new NullPointerException((String) null));
|
||||||
|
@ -107,12 +128,40 @@ public class JschSshClientTest {
|
||||||
assert !ssh.causalChainHasMessageContaining(new NullPointerException()).apply(" End of IO Stream Read");
|
assert !ssh.causalChainHasMessageContaining(new NullPointerException()).apply(" End of IO Stream Read");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Seems to be using oauth now instead of bouncycastle and is more strict.
|
||||||
|
// Commands used to generate this key are:
|
||||||
|
// openssl dsaparam -outform PEM 2048 > dsaparams
|
||||||
|
// openssl gendsa -aes256 -out privkey.pem dsaparams
|
||||||
|
private static final String key = "-----BEGIN DSA PRIVATE KEY-----\n" +
|
||||||
|
"Proc-Type: 4,ENCRYPTED\n" +
|
||||||
|
"DEK-Info: AES-256-CBC,8C3A84B8BDA9FE69AAB4A322D7795161\n" +
|
||||||
|
"\n" +
|
||||||
|
"B8nuwNIcw5UtV9gGX2LiOq5OZ0uDgWsRon/mmWu+8EFd6X1aautVw8pCZuNusNkS\n" +
|
||||||
|
"GZlO1JBIgKdX6Qqx0cPsirFB7GTNbBVHOIMqYbmQKW5Ju+n+NkNIomDJDJqBWknE\n" +
|
||||||
|
"ZIkegznvdLN11r6F4jreusnVepSNYeRwKxA5KAT0S6XsgVFKSJZIyJj8EKZl/25D\n" +
|
||||||
|
"a7LKoYRlf5QK+Q1/zmMyZcCt0irIMcHxslpVlyATajAADB0hwBl4Xh0H3oHR3PU1\n" +
|
||||||
|
"xhsliYTARGov6Wn7adDCG9zWDzO7cX3941ub0FPoDdPLxGkmwqEwijF1XWvYbIUC\n" +
|
||||||
|
"EBjomG3pwjC1kfoqAYJhThi8vmQYtFyCagcZMauHDKuqwUr1o3jS51PBe3bKeg4M\n" +
|
||||||
|
"dP/JSTiTAUGtwV/MobThQFvCWJm22jIR6Eb0IYPcncUQuZ1QO2piwSvMUZZYCFX/\n" +
|
||||||
|
"uY7fHkPZyBkZIrxGc91jhSQlo8qsVBIThJpLYI2M2PjKxTzsgZ2mWWK/Zm7pVqqI\n" +
|
||||||
|
"ldTJ1cpSMb2/9BsXF0CWvzaC4qN5Ymmrp152M4ZEnsRN3ycd9wFCD2cM7w5frj4Z\n" +
|
||||||
|
"3Q3M9/qNYuPfHddJa1DIkYpZxTTzOo4BBWx2O32D3in+2YZWjBgdxej17hKVkmUR\n" +
|
||||||
|
"C432CtEqUYAtVv//3TZ47hYsywvvVEX/3ljcCObrHKDha6i3SwXMqe1tL3BYexOn\n" +
|
||||||
|
"LS8aGQ148oekWaSWYrXCo0gjuJgY3hJZKUHoKdhvyW/FZG3rMjk5NlU9IwjMweqz\n" +
|
||||||
|
"Bznl7sMxHqtW4BPV9fM4uaiM8LOMkIm6euu/1a2o///TaEgFr/H1ybLdcg8Au1Iy\n" +
|
||||||
|
"sH68Xn+pmkx1bdVCCpi44EtAEHrpX11AC+cuvu8KG0A+Tpy3WW7YXYkregEQM3kF\n" +
|
||||||
|
"XzzyJfHuZKvM7qXsMnt/T5VCYX1LSEtXFABFMHDsPC9qs1LVLdSC5U0Ux0Ac0Sqq\n" +
|
||||||
|
"MRG2Yc8hDOPvPOmiqD9OK9PC6fa+bbMEtlS2O5Cd0l+hoE8OD1EFP1hAGQ0ivjZT\n" +
|
||||||
|
"zMJXBUVUtYAkrpU6NcY+ub7IyYBR3wOWSAUbolx3K4p2o8k3MGFdLHb4dGvypIv2\n" +
|
||||||
|
"oHhZLNLYGPrAN2g0gpNmlepDS1aG6422770O/Eh1bDXDyGYJRW3INwWenN8KbuYd\n" +
|
||||||
|
"-----END DSA PRIVATE KEY-----";
|
||||||
|
|
||||||
public void testPrivateKeyWithPassphrase() throws UnknownHostException {
|
public void testPrivateKeyWithPassphrase() throws UnknownHostException {
|
||||||
Injector i = Guice.createInjector(module());
|
Injector i = Guice.createInjector(module(),new SLF4JLoggingModule());
|
||||||
SshClient.Factory factory = i.getInstance(SshClient.Factory.class);
|
SshClient.Factory factory = i.getInstance(SshClient.Factory.class);
|
||||||
try {
|
try {
|
||||||
JschSshClient ssh = JschSshClient.class.cast(factory.create(new IPSocket("localhost", 22), new Credentials(
|
JschSshClient ssh = JschSshClient.class.cast(factory.create(new IPSocket("localhost", 22), new Credentials(
|
||||||
"username", "-----BEGIN RSA PRIVATE KEY-----\nProc-Type: 4,ENCRYPTED\nDEK-Info: AES-128-CBC,123\n\n123")));
|
"username", key)));
|
||||||
ssh.connect();
|
ssh.connect();
|
||||||
assert false; // this code should never be reached.
|
assert false; // this code should never be reached.
|
||||||
} catch (SshException e) {
|
} catch (SshException e) {
|
||||||
|
|
|
@ -21,6 +21,7 @@ package org.jclouds.ssh.jsch.config;
|
||||||
import java.net.UnknownHostException;
|
import java.net.UnknownHostException;
|
||||||
|
|
||||||
import org.jclouds.domain.Credentials;
|
import org.jclouds.domain.Credentials;
|
||||||
|
import org.jclouds.logging.slf4j.config.SLF4JLoggingModule;
|
||||||
import org.jclouds.net.IPSocket;
|
import org.jclouds.net.IPSocket;
|
||||||
import org.jclouds.ssh.SshClient;
|
import org.jclouds.ssh.SshClient;
|
||||||
import org.jclouds.ssh.jsch.JschSshClient;
|
import org.jclouds.ssh.jsch.JschSshClient;
|
||||||
|
@ -39,7 +40,7 @@ public class JschSshClientModuleTest {
|
||||||
|
|
||||||
public void testConfigureBindsClient() throws UnknownHostException {
|
public void testConfigureBindsClient() throws UnknownHostException {
|
||||||
|
|
||||||
Injector i = Guice.createInjector(new JschSshClientModule());
|
Injector i = Guice.createInjector(new JschSshClientModule(), new SLF4JLoggingModule());
|
||||||
SshClient.Factory factory = i.getInstance(SshClient.Factory.class);
|
SshClient.Factory factory = i.getInstance(SshClient.Factory.class);
|
||||||
SshClient connection = factory.create(new IPSocket("localhost", 22), new Credentials("username", "password"));
|
SshClient connection = factory.create(new IPSocket("localhost", 22), new Credentials("username", "password"));
|
||||||
assert connection instanceof JschSshClient;
|
assert connection instanceof JschSshClient;
|
||||||
|
|
|
@ -0,0 +1,15 @@
|
||||||
|
<?xml version="1.0"?>
|
||||||
|
<configuration>
|
||||||
|
<appender name="FILE" class="ch.qos.logback.core.FileAppender">
|
||||||
|
<file>target/test-data/jclouds-ssh.log</file>
|
||||||
|
<append>true</append>
|
||||||
|
<encoder>
|
||||||
|
<pattern>%-4relative [%thread] %-5level %logger{35} - %msg%n</pattern>
|
||||||
|
</encoder>
|
||||||
|
</appender>
|
||||||
|
<logger name="jclouds.ssh" level="TRACE"/>
|
||||||
|
<logger name="net.schmizz" level="INFO"/>
|
||||||
|
<root level="INFO">
|
||||||
|
<appender-ref ref="FILE"/>
|
||||||
|
</root>
|
||||||
|
</configuration>
|
Loading…
Reference in New Issue