2

I am using JSch exec channel to login to multiple servers and run few commands. Then I need to capture the output and store it in a file called log. For some odd reason, the file remains blank after executing.

try (OutputStream log = new BufferedOutputStream(new FileOutputStream(outputFilePath))) {
    ArrayList<String> lists = new ArrayList<String>();
    lists.add("hostname");
    lists.add("df -l");
    String host ="localhost";

    JSch jsch = new JSch();
    try {
        String user = "user";
        String password = "pass";
        Session session = jsch.getSession(user, host, 22);
        session.setPassword(password);
        session.setConfig(getProperties());
        session.setTimeout(20 * 1000);
        System.out.println(session.getTimeout());
        session.connect();
        if (session.isConnected()) {
            System.out.println(host + " Session Established ");
        }

        for (String elem : lists) {
            Channel channel = session.openChannel("exec");
            channel.setOutputStream(log);

            ((ChannelExec) channel).setCommand(elem);

            channel.setInputStream(null);

            ((ChannelExec) channel).setErrStream(System.err);

            InputStream in = channel.getInputStream();

            channel.connect();

            byte[] tmp = new byte[1024];
            while (true) {
                while (in.available() > 0) {
                    int i = in.read(tmp, 0, 1024);
                    if (i < 0) {
                        break;
                    }
                    System.out.print(new String(tmp, 0, i));
                }
                if (channel.isClosed()) {
                    if (in.available() > 0) {
                        continue;
                    }
                    System.out.println("exit-status: " + channel.getExitStatus());
                    break;
                }
                try {
                    Thread.sleep(1000);
                } catch (Exception ee) {
                }
            }
            channel.disconnect();
        }

        session.disconnect();

The program displays the output via the IDE console, but the output file gets created but it remains blank.

Then I set the system.setOut to a file, this prevented the console from displaying anymore more data but the output.txt file remains blank.

System.setOut(new PrintStream(new BufferedOutputStream(new FileOutputStream("output.txt"))));
Martin Prikryl
  • 188,800
  • 56
  • 490
  • 992
Moe
  • 1,427
  • 4
  • 34
  • 54
  • Why not use a logging library? It would probably be easier... – assylias Jan 16 '16 at 23:03
  • Do you have an example or a link to use as reference? – Moe Jan 16 '16 at 23:06
  • For example: http://stackoverflow.com/questions/15758685/how-to-write-logs-in-text-file-when-using-java-util-logging-logger - but if you google "java log to file example" I'm sure you will find plenty of examples. – assylias Jan 16 '16 at 23:12

1 Answers1

2

It's because the getInputStream overrides the setOutputStream call.

See how these methods are implemented in JSch (both end up calling io.setOutputStream):

public void setOutputStream(OutputStream out){
  io.setOutputStream(out, false);
}

public InputStream getInputStream() throws IOException {
  int max_input_buffer_size = 32*1024;
  try {
    max_input_buffer_size =
      Integer.parseInt(getSession().getConfig("max_input_buffer_size"));
  }
  catch(Exception e){}
  PipedInputStream in =
    new MyPipedInputStream(
                           32*1024,  // this value should be customizable.
                           max_input_buffer_size
                           );
  boolean resizable = 32*1024<max_input_buffer_size;
  io.setOutputStream(new PassiveOutputStream(in, resizable), false);
  return in;
}

I assume you actually do not need that output reading block based on InputStream in. Just remove it and the log file writing should start working.


Side note: The output stream will be closed by default with the channel. As you reuse the same stream for multiple channels, you should prevent that.

Use an override of the setOutputStream with dontclose argument:

public void setOutputStream(OutputStream out, boolean dontclose)

like this:

channel.setOutputStream(log, true);
Martin Prikryl
  • 188,800
  • 56
  • 490
  • 992