j2ssh实现日志搜索

批量查询日志的脚本,自己用着还行,如果给别人也还需要复制一份。如能够把多台机器的日志搜索做成web后台,这样就方便了。

上篇博客解决了登录服务器的信任登录交互问题,那么我们就能够更方便的登录到机器上执行命令。这里我用的是SSHTools ,它是一组 Java 的 SSH 应用和开发包,包括:Java SSH API, SSH Terminal, SSH secured VNC client, SFTP client and SSH Daemon。

 

POM中引入sshtools:

<dependency>
    <groupId>sshtools</groupId>
    <artifactId>j2ssh-core</artifactId>
    <version>0.2.9</version>
</dependency>

 1、j2ssh有2种登录验证方式:PublicKeyAuthenticationClient(公钥)、PasswordAuthenticationClient(密码),验证通过之后获得session,用来向服务器发送命令

SessionChannelClient session = null;
		try {
			PublicKeyAuthenticationClient auth = new PublicKeyAuthenticationClient();
			auth.setUsername("username");
			SshPrivateKeyFile file = SshPrivateKeyFile.parse(new File(privateKeyFile));
			SshPrivateKey key = file.toPrivateKey("");
			auth.setKey(key);
			if(ssh.authenticate(auth) == AuthenticationProtocolState.COMPLETE){
				session = ssh.openSessionChannel();
				if(session.startShell()){
					return session;
				}
			}
		} catch (IOException e) {
			//TODO
		}

 

 2、根据参数组合命令,命令行末尾要带换行符'\n'

 

public static void doInput(String host, String queryStr, String logFullPath,
			int n, SessionChannelClient session, SshResult result) {
		OutputStream out = session.getOutputStream();
		StringBuilder cmd = new StringBuilder("ssh username@");
		cmd.append(host).append(" ");
		if(n == 0){
			cmd.append("'grep \"").append(queryStr).append("\" ").append(logFullPath);
		}else{
			cmd.append("'grep -C ").append(n).append(" \"").append(queryStr).append("\" ").append(logFullPath);
		}
		cmd.append("'\n");
		result.setCmd(cmd.toString());
		try {
			out.write(cmd.toString().getBytes());
			out.flush();
			out.write(SshConfig.ExitCMD.getBytes());
			out.flush();
		} catch (IOException e) {
			e.printStackTrace();
		} finally{
			try {
				out.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}
 

 

 3、启用1个线程来读取session的流数据,主线程等待3s,超时后子线程也就终止执行,这样是为了解决BufferedReader阻塞的问题,这样处理会遇到2个问题:

1)数据量大,3s内数据处理不完:根据关键字查询日志,该关键字一般都是唯一的,其对应的返回结果都很少的,如果数据量大的话则不建议也没必要批量查询

2)执行时间:如果日志很少,查询执行很快,但还是要等待3s时间。有没有别的方法呢?

 

public static void doOutput(SessionChannelClient session, SshResult result) {
		try {
			new SshResHandler(session.getInputStream(), result).start();
			Thread.sleep(3000);
		} catch( Throwable e){
			e.printStackTrace();
		} finally{
			if(session != null){
				try {
					session.close();
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		}
	}
-------------------------------------
SshResHandler.java
@Override
		public void run() {
			int i=0;
			String line;
			StringBuilder searchRes = new StringBuilder();
			result.setResult(searchRes);
			try {
				while ((line = in.readLine()) != null && line.trim().length()>0) {
					//System.out.println(i++ + ":" + line);
					searchRes.append(line).append("\n");
					result.setRows(i++);
					if( i > SshConfig.maxLine){
						break;
					}
				}
			} catch (Exception e) {
				e.printStackTrace();
			} finally{
				try {
					this.in.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
			
		}
 

 

***********************************

BufferedReader的阻塞问题

 

this.in = new BufferedReader(new InputStreamReader(inputStream));
while ((line = in.readLine()) != null) {
	System.out.println(i++ + ":" + line);
	searchRes.append(line).append("\n");
} 
System.out.println("xxxx");

 

 如果是读取普通的文件,则没有问题,一直读到文件末尾,in.readLine()返回null,则while循环终止。但这里程序一直阻塞了,始终执行不到while后面的代码。

如:BufferedReader br = new BufferedReader(new InputStreamReader(p.getErrorStream())),参考别人的解释,这里获取子进程的标准错误输出流,但jvm一直没有读取,缓冲区满了后就无法继续写入数据。错误输出流没有数据要输出,标准输出流有数据要输出,但由于标准输出流没有被读取,进程就不会结束,错误输出流也不会关闭,于是在执行到**readLine()**方法,这个程序就会被阻塞。

 

参考文章:

http://cnupdog.com/category/programming/

http://blog.csdn.net/dyc9891009/article/details/8141200

 

 

你可能感兴趣的:(ssh)